WireMock으로 개발·테스트에서 API 서비스 목킹하기
WireMock으로 개발·테스트에서 API 서비스 목킹하기
로컬 개발과 테스트 중에는 앱이 원격 API에 의존하는 상황을 자주 만나요. 네트워크 문제, 속도 제한, API 제공자의 다운타임이 진행을 막을 수 있어요. WireMock은 실제 API의 동작을 시뮬레이션하는 목 서버를 만들어 개발과 테스트의 통제된 환경을 제공하는 오픈소스 도구예요.
출처: 문서
본문
API와 프론트엔드 앱이 모두 있고, 프론트엔드가 API와 어떻게 상호작용하는지 테스트하고 싶다고 생각해봐요. WireMock으로 목 서버를 설정해 API의 응답을 시뮬레이션하면, 실제 API에 의존하지 않고도 프론트엔드 동작을 테스트할 수 있어요. API가 아직 개발 중이거나 실제 API에 영향을 주지 않고 여러 시나리오를 테스트하고 싶을 때 특히 유용해요. WireMock은 HTTP와 HTTPS 프로토콜을 모두 지원하며 지연, 오류, 다양한 HTTP 상태 코드를 포함한 여러 응답 시나리오를 시뮬레이션할 수 있어요.
이 가이드에서 배울 내용:
- Docker로 WireMock 컨테이너를 시작하기
- 외부 API에 의존하지 않고 로컬 개발에서 목 데이터 사용하기
- 프로덕션에서 AccuWeather의 실시간 날씨 데이터를 가져오는 라이브 API 사용하기
Docker에서 WireMock 사용하기
WireMock의 공식 Docker 이미지는 WireMock 인스턴스를 배포하고 관리하는 편리한 방법을 제공해요. WireMock은 amd64, armv7, armv8을 포함한 다양한 CPU 아키텍처를 지원해 서로 다른 기기와 플랫폼에서의 호환성을 보장해요. WireMock standalone에 대해 더 알아보려면 WireMock 문서 사이트를 참고해요.
사전 준비 (Prerequisites)
이 하우투 가이드를 따라 하려면 다음이 필요해요.
- Docker Desktop
WireMock 시작하기
다음 단계로 WireMock의 빠른 데모를 시작해요.
GitHub 저장소를 로컬에 클론해요.
$ git clone https://github.com/dockersamples/wiremock-node-docker
wiremock-endpoint 디렉터리로 이동해요.
$ cd wiremock-node-docker/
WireMock은 백엔드가 데이터를 가져오기 위해 통신하는 목 API 역할을 해요. 목 API 응답은 mappings 디렉터리에 이미 만들어져 있어요.
클론한 프로젝트 디렉터리 루트에서 다음 명령을 실행해 Compose 스택을 시작해요.
$ docker compose up -d
잠시 후 애플리케이션이 실행됩니다. wiremock-node-docker 컨테이너를 선택해 로그를 확인할 수 있어요.
목 API를 테스트해요.
$ curl http://localhost:8080/api/v1/getWeather?city=Bengaluru
목 데이터가 담긴 다음 캔드(canned) 응답을 반환할 거예요.
{"city":"Bengaluru","temperature":27.1,"conditions":"Mostly cloudy","forecasts":[{"date":"2024-09-02T07:00:00+05:30","temperature":83,"conditions":"Partly sunny w/ t-storms"},{"date":"2024-09-03T07:00:00+05:30","temperature":83,"conditions":"Thunderstorms"},{"date":"2024-09-04T07:00:00+05:30","temperature":83,"conditions":"Intermittent clouds"},{"date":"2024-09-05T07:00:00+05:30","temperature":82,"conditions":"Dreary"},{"date":"2024-09-06T07:00:00+05:30","temperature":82,"conditions":"Dreary"}]}
WireMock에서는 매핑 파일로 캔드 응답을 정의해요. 이 요청에 대한 목 데이터는 wiremock-endpoint/mappings/getWeather/getWeatherBengaluru.json의 JSON 파일에 정의되어 있어요. 캔드 응답 스텁에 대해 더 알아보려면 WireMock 문서를 참고해요.
개발에서 WireMock 사용하기
이제 WireMock을 사용해봤으니 개발과 테스트에 사용해볼게요. 이 예시에서는 Node.js 백엔드가 있는 샘플 애플리케이션을 사용해요. 이 앱 스택의 구성:
- 로컬 개발 환경: Node.js 백엔드와 WireMock이 실행되는 컨텍스트
- Node.js 백엔드: HTTP 요청을 처리하는 백엔드 애플리케이션
- 외부 AccuWeather API: 실제 날씨 데이터를 가져오는 실제 API
- WireMock: 테스트 중 API 응답을 시뮬레이션하는 목 서버. Docker 컨테이너로 실행돼요.
개발에서는 Node.js 백엔드가 실제 AccuWeather API 대신 WireMock에 요청을 보내요. 프로덕션에서는 실제 데이터를 위해 라이브 AccuWeather API에 직접 연결해요.
로컬 개발에서 목 데이터 사용하기
Node 앱을 설정해 실제 AccuWeather API 대신 WireMock 컨테이너에 요청을 보내볼게요.
사전 준비: Node.js와 npm 설치, WireMock 컨테이너가 실행 중인지 확인(위 "WireMock 시작" 참고)
컨테이너화되지 않은 Node 애플리케이션을 설정하는 단계를 따라가요.
accuweather-api 디렉터리로 이동해요. package.json 파일이 있는 디렉터리에 있는지 확인해요.
환경 변수를 설정해요. accuweather-api/ 디렉터리 아래의 .env 파일을 열어요. 기존 항목을 제거하고 다음 한 줄만 포함하도록 해요.
API_ENDPOINT_BASE=http://localhost:8080
이렇게 하면 Node.js 애플리케이션이 API 호출에 WireMock 서버를 사용하게 돼요.
애플리케이션 진입점 살펴보기
애플리케이션의 메인 파일은 accuweather-api/src/api 디렉터리의 index.js예요. 이 파일은 Node.js 애플리케이션에 필수적인 getWeather.js 모듈을 시작해요. dotenv 패키지를 사용해 .env 파일에서 환경 변수를 로드해요. API_ENDPOINT_BASE 값에 따라 애플리케이션은 요청을 WireMock 서버(http://localhost:8080)나 AccuWeather API로 라우팅해요. 이 설정에서는 WireMock 서버를 사용해요. 이 코드는 애플리케이션이 WireMock을 사용하지 않을 때만 ACCUWEATHER_API_KEY가 필요하도록 보장해서 효율성을 높이고 오류를 피해요.
require("dotenv").config();
const express = require("express");
const axios = require("axios");
const router = express.Router();
const API_ENDPOINT_BASE = process.env.API_ENDPOINT_BASE;
const API_KEY = process.env.ACCUWEATHER_API_KEY;
console.log('API_ENDPOINT_BASE:', API_ENDPOINT_BASE); // Log after it's defined
console.log('ACCUWEATHER_API_KEY is set:', !!API_KEY); // Log boolean instead of actual key
if (!API_ENDPOINT_BASE) {
throw new Error("API_ENDPOINT_BASE is not defined in environment variables");
}
// Only check for API key if not using WireMock
if (API_ENDPOINT_BASE !== 'http://localhost:8080' && !API_KEY) {
throw new Error("ACCUWEATHER_API_KEY is not defined in environment variables");
}
// Function to fetch the location key for the city
async function fetchLocationKey(townName) {
const { data: locationData } = await axios.get(
`${API_ENDPOINT_BASE}/locations/v1/cities/search`,
{
params: {
q: townName,
details: false,
apikey: ***,
},
}
);
return locationData[0]?.Key;
}
Node 서버 시작하기
Node 서버를 시작하기 전에 package.json에 나열된 노드 패키지를 npm install로 설치했는지 확인해요.
npm install
npm run start
다음 출력이 보여야 해요.
> [email protected] start
> node src/index.js
API_ENDPOINT_BASE: http://localhost:8080
.. Listening: http://localhost:5001
이 출력은 Node 애플리케이션이 성공적으로 시작됐음을 나타내요. 이 터미널 창을 열어 두세요.
목 API 테스트하기
새 터미널 창을 열고 다음 명령을 실행해 목 API를 테스트해요.
$ curl "http://localhost:5001/api/v1/getWeather?city=Bengaluru"
다음 출력이 보여야 해요.
{"city":"Bengaluru","temperature":27.1,"conditions":"Mostly cloudy","forecasts":[{"date":"2024-09-02T07:00:00+05:30","temperature":83,"conditions":"Partly sunny w/ t-storms"},{"date":"2024-09-03T07:00:00+05:30","temperature":83,"conditions":"Thunderstorms"},{"date":"2024-09-04T07:00:00+05:30","temperature":83,"conditions":"Intermittent clouds"},{"date":"2024-09-05T07:00:00+05:30","temperature":82,"conditions":"Dreary"},{"date":"2024-09-06T07:00:00+05:30","temperature":82,"conditions":"Dreary"}]}%
이는 Node.js 애플리케이션이 이제 WireMock 컨테이너로 요청을 라우팅하고 목 응답을 받고 있음을 나타내요.
포트 8080 대신 http://localhost:5001 URL을 사용하고 있다는 걸 눈치챘을 거예요. 이는 Node.js 애플리케이션이 포트 5001에서 실행되면서 포트 8080에서 듣고 있는 WireMock 컨테이너로 요청을 라우팅하기 때문이에요.
팁: 다음 단계로 진행하기 전에 node 애플리케이션 서비스를 중지하세요.
프로덕션에서 라이브 API 사용해 AccuWeather 실시간 날씨 데이터 가져오기
애플리케이션에 실시간 날씨 데이터를 더하려면 AccuWeather API를 매끄럽게 통합할 수 있어요. 이 섹션은 컨테이너화되지 않은 Node.js 애플리케이션을 설정하고 AccuWeather API에서 날씨 정보를 직접 가져오는 단계를 안내해요.
AccuWeather API 키 만들기
https://developer.accuweather.com/ 에서 무료 AccuWeather 개발자 계정에 가입해요. 계정에서 상단 탐색 메뉴의 MY APPS를 선택해 새 앱을 만들어 고유한 API 키를 얻어요. AccuWeather API는 실시간 날씨 데이터와 예보를 제공하는 웹 API예요. 개발자는 이 API를 사용해 날씨 정보를 자신의 애플리케이션, 웹사이트, 다른 프로젝트에 통합할 수 있어요.
accuweather-api 디렉터리로 변경해요.
$ cd accuweather-api
.env 파일로 AccuWeather API 키를 설정해요.
팁: 충돌을 막으려면
.env파일을 수정하기 전에API_ENDPOINT_BASE나ACCUWEATHER_API_KEY라는 기존 환경 변수를 제거하세요.
터미널에서 다음 명령을 실행해요.
unset API_ENDPOINT_BASE
unset ACCUWEATHER_API_KEY
.env 파일에서 환경 변수를 설정할 차례예요.
ACCUWEATHER_API_KEY=XXXXXX
API_ENDPOINT_BASE=http://dataservice.accuweather.com
ACCUWEATHER_API_KEY에 올바른 값을 넣어야 해요.
의존성 설치하기
다음 명령을 실행해 필요한 패키지를 설치해요.
$ npm install
이 명령은 package.json에 나열된 모든 패키지를 설치해요. 이 패키지들은 프로젝트가 제대로 동작하는 데 필수적이에요. 사용 중단(deprecated)된 패키지와 관련된 경고가 나오면 이 데모에서는 무시해도 돼요.
실행 중인 기존 Node 서버가 없다고 가정하고 다음 명령으로 Node 서버를 시작해요.
$ npm run start
다음 출력이 보여야 해요.
> [email protected] start
> node src/index.js
API_ENDPOINT_BASE: http://dataservice.accuweather.com
ACCUWEATHER_API_KEY is set: true
Listening: http://localhost:5001
이 터미널 창을 열어 두세요.
curl 명령을 실행해 서버 URL에 GET 요청을 보내요. 새 터미널 창에서 다음 명령을 입력해요.
$ curl "http://localhost:5000/api/v1/getWeather?city=Bengaluru"
이 명령은 로컬 서버가 Bengaluru라는 도시의 날씨 데이터를 제공하라고 요청하는 거예요. 요청은 /api/v1/getWeather 엔드포인트를 대상으로 하고, 쿼리 매개변수 city=Bengaluru를 제공해요. 명령을 실행하면 서버가 이 요청을 처리하고 데이터를 가져와 curl이 터미널에 표시할 응답으로 반환해요. 외부 AccuWeather API에서 데이터를 가져올 때는 최신 날씨 조건을 반영한 실시간 데이터와 상호작용하게 돼요.
요약 (Recap)
이 가이드는 Docker로 WireMock을 설정하는 방법을 안내했어요. 외부 서비스에 의존하지 않고 애플리케이션을 개발하고 테스트할 수 있도록 API 엔드포인트를 시뮬레이션하는 스텁을 만드는 방법을 배웠어요. WireMock을 사용하면 안정적이고 일관된 테스트 환경을 만들고, 엣지 케이스를 재현하며, 개발 워크플로를 빠르게 할 수 있어요.