“매번 curl로 API 테스트하기 귀찮아서 만들기 시작했는데…”
여러 API들을 구현하고 나니, 큐 상태를 확인하거나 테스트할 때마다 매번 curl 명령어를 치고 있더라고요.
# 매일매일 반복하던 명령어들...
curl -X GET "http://localhost:8080/api/v1/queues" -H "X-API-Key: test-tenant-key"
curl -X POST "http://localhost:8080/api/v1/queues/test-queue/messages" \
-H "Content-Type: application/json" \
-H "X-API-Key: test-tenant-key" \
-d '{"messageBody": "test message"}'
curl -X GET "http://localhost:8080/api/v1/queue"
-H "X-API-Key: test-tenant-key"
이건 아니다 싶더라구요… Admin 페이지를 만들어야 겠다고 생각했습니다.
이번 포스트에서는 curl 안치기 위해 시작된 간단한 도구가 쓸만하게 변한 내용을 공유해보겠습니다.
🤦♂️ 1단계: “curl 치기 너무 귀찮다…”
처음의 솔직한 동기
개발하면서 큐를 테스트하려면 매번 이런 과정을 거쳐야 했어요
# 1. 큐 목록 확인
curl -X GET "http://localhost:8080/api/v1/queues" \
-H "X-API-Key: test-tenant-key" | jq
# 2. 메시지 전송
curl -X POST "http://localhost:8080/api/v1/queues/my-queue/messages" \
-H "Content-Type: application/json" \
-H "X-API-Key: test-tenant-key" \
-d '{"messageBody": "test message"}'
# 3. 메시지 수신
curl -X GET "http://localhost:8080/api/v1/queues/my-queue/messages" \
-H "X-API-Key: test-tenant-key"
# 4. 큐 상태 확인
curl -X GET "http://localhost:8080/api/v1/queues/my-queue/stats" \
-H "X-API-Key: test-tenant-key" | jq
몇 번 하다 보니: “이거 버튼 클릭으로 할 수 없나?” 하는 생각이 들더라고요.
첫 번째 버전: 정말 단순한 테스트 도구
// 정말로 이렇게 시작했습니다... 테스트용 도구
function QuickTester() {
const [apiKey, setApiKey] = useState('test-tenant-key');
const [queueName, setQueueName] = useState('my-queue');
const [message, setMessage] = useState('test message');
const [response, setResponse] = useState('');
const sendMessage = async () => {
try {
const res = await fetch(`/api/v1/queues/${queueName}/messages`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({ messageBody: message })
});
const data = await res.text();
setResponse(data);
} catch (error) {
setResponse(`Error: ${error}`);
}
};
const receiveMessage = async () => {
try {
const res = await fetch(`/api/v1/queues/${queueName}/messages`, {
headers: { 'X-API-Key': apiKey }
});
const data = await res.text();
setResponse(data);
} catch (error) {
setResponse(`Error: ${error}`);
}
};
return (
<div>
...
</div>
);
}
결과: 확실히 curl보다는 편했어요!
첫 번째 문제: “큐가 여러 개인데 하나씩 테스트하기 번거롭다”
테스트 도구를 쓰다 보니 또 다른 불편함이…
큐 목록:
- test-queue
- test-queue2
- test-queue3
- ...
- ...
큐마다 일일이 이름을 바꿔서 테스트하기 귀찮더라고요.
두 번째 버전: 큐 목록도 보여주자
// 조금 더 발전된 형태
function QueueTester() {
const [queues, setQueues] = useState([]);
const [selectedQueue, setSelectedQueue] = useState('');
const [apiKey, setApiKey] = useState('test-tenant-key');
const [testResults, setTestResults] = useState({});
// 큐 목록 가져오기
const fetchQueues = async () => {
try {
const response = await fetch('/api/v1/queues', {
headers: { 'X-API-Key': apiKey }
});
const data = await response.json();
setQueues(data.queues || []);
} catch (error) {
console.error('큐 목록 조회 실패:', error);
}
};
// 큐 상태 확인
const checkQueueStats = async (queueName) => {
try {
const response = await fetch(`/api/v1/queues/${queueName}/stats`, {
headers: { 'X-API-Key': apiKey }
});
const stats = await response.json();
setTestResults(prev => ({
...prev,
[queueName]: stats
}));
} catch (error) {
console.error('큐 상태 조회 실패:', error);
}
};
return (
<div>
...
</div>
);
}
어라?… 재밌을지도?…
2단계: “좀 더 해볼까?…”
문제: “매번 새로고침하기 귀찮다”
테스트 도구를 쓰다 보니 이런 패턴이 반복되더라고요:
- 메시지 보내기
- 브라우저 새로고침 (큐 상태 확인)
- 메시지 받기
- 브라우저 새로고침 (큐 상태 확인)
생각: “이거 자동으로 업데이트되면 좋겠는데?”
해결: 폴링으로 자동 업데이트
// 자동 새로고침 기능 추가
const useAutoRefresh = (fetchFn, interval = 3000) => {
const [data, setData] = useState(null);
const [isEnabled, setIsEnabled] = useState(true);
useEffect(() => {
if (!isEnabled) return;
const poll = async () => {
try {
const result = await fetchFn();
setData(result);
} catch (error) {
console.error('폴링 에러:', error);
}
};
poll(); // 즉시 실행
const intervalId = setInterval(poll, interval);
return () => clearInterval(intervalId);
}, [isEnabled, fetchFn, interval]);
return { data, isEnabled, setIsEnabled };
};
// 사용
function QueueDashboard() {
const [apiKey, setApiKey] = useState('test-tenant-key');
const fetchQueues = useCallback(() =>
fetch('/api/v1/queues', {
headers: { 'X-API-Key': apiKey }
}).then(res => res.json())
, [apiKey]);
const { data: queuesData, isEnabled, setIsEnabled } = useAutoRefresh(fetchQueues);
return (
<div>
...
</div>
);
}
🎨 3단계: “안 이뻐~~ ㅜㅜ”
문제: “디자인이 구리다”
JSON 그대로 보여줬더니 내가 보기가 싫다
// ❌ 개발자에게만 친숙한 UI
<div>
<pre>{JSON.stringify(queueStats, null, 2)}</pre>
</div>
// 결과:
// {
// "messageCount": 1542,
// "dlqCount": 23,
// "processingCount": 8
// }
해결: 이쁜 디자인으로 변경
// ✅ 보기 좋은 카드 형태
const QueueCard = ({ queue }: { queue: QueueInfo }) => {
return (
<div>
...
</div>
);
};
두 번째 깨달음: “색이 문제여..”
메인 화면 색 변경:
- 배경 색: linear-gradient(135deg, #667eea 0%, #764ba2 100%)
- 버튼 색: background-color: #3b82f6;
- 활성 색: background-color: #d1fae5;
- 비활성 색: background-color: #fee2e2;
4단계: “유저 테스트도 해야하는데…”
문제: “유저도 잘 만들어지나 테스트 해봐야하는데…”
문제점들:
- 유저 리스트 출력
- 유저 생성
- 유저 별 토픽 리스트 출력?
해결: 하드코딩이지만 일단 동작하는 형태
1번 2번은 구현 => 큐에서 만들었던 디자인 비슷하게 구현 3번은 귀찮아서 하드코딩 => 첫번째 유저의 토픽만 출력
// 실제 구현: 간단한 하드코딩 방식
const API_KEY = 'test-api-key'; // 개발용 고정 키
const api = axios.create({
baseURL: 'http://localhost:8080',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY, // 고정된 API 키 사용
},
});
export const sqsApi = {
listQueues: async () => {
const response = await api.get('/api/v1/queues');
return response.data;
},
sendMessage: async (queueName: string, message: any) => {
const response = await api.post(`/api/v1/queues/${queueName}/messages`, message);
return response.data;
}
// ... 나머지 API들
};
🚀 다음 편 예고
다음 편에서는 큐에서 Redis를 쓰는게 맞을지… 고민했던 순간과 이를 해결하기 위해 생각했던 과정을 자세히 다뤄보겠습니다.
Admin 페이지도 계속 발전시켜 볼까나..
- 더 편리한 테스트 기능들
- 간단한 모니터링 개선
- 사용자 경험 향상 (조금씩…)
💬 댓글