MSW를 활용하여 웹 브라우저에서 Mockup 사용하기. API 의존으로부터의 해방.
목차 펼치기
왜 Mockup인가?
왜 Mockup인가?
어쩔 수 없이 프론트의 개발은 API 응답에 의존적인 부분들이 많다. 하지만 이어달리기처럼 [기획]-[디자인]-[백엔드]-[프론트엔드]의 개발 흐름이 직렬로 흐르도록 기다려주지 않는다. 최대한 병렬로 진행하여 가능한 한 빠르게 모든 결과물을 확인하기를 원한다. 그렇기 때문에 프론트는 API가 제대로 다 나오지 않았음에도 API에 의존적인 UI를 개발하고, 디자이너와 디자인 검수를 진행해야 할 때가 많다. 이럴 때는 보통 두 가지 방법을 사용한다.
백엔드 개발자가 API의 응답에 가상 데이터를 먼저 보내준다.
프론트엔드 개발자가 API 응답 형식에 맞춰 가상 데이터를 만든다.
특히 2번의 방법은 API 응답에 대한 다양한 케이스들을 테스트 해야할 때 사용하기도 한다.
두 가지 방법 모두 전제조건은
백엔드 개발자와 미리 데이터 양식을 맞춰 놓아야 한다는 것이다. 이 때의 가상 데이터를 Mockup 데이터라고 한다. Mockup의 사전상 정의는
비행기·자동차 등의 개발 단계에서, 각 부의 배치를 보다 실제적으로 검토하기 위해서 제작되는 실물 크기의 모형.
이다.
왜 MSW 인가?
왜 MSW 인가?
![출처: 공식 홈페이지( https://mswjs.io/ )](https://treefeely.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fad9b6331-a1bf-4510-ab6e-afe732ede744%2Fc18c820d-66e0-4bda-934b-2bb11fc95f39%2FUntitled.png%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Content-Sha256%3DUNSIGNED-PAYLOAD%26X-Amz-Credential%3DAKIAT73L2G45HZZMZUHI%252F20240730%252Fus-west-2%252Fs3%252Faws4_request%26X-Amz-Date%3D20240730T123504Z%26X-Amz-Expires%3D3600%26X-Amz-Signature%3D7b62ce8716610e6b667acb7a847953f7ddb04183bf0a13b04324a1a20efde801%26X-Amz-SignedHeaders%3Dhost%26x-id%3DGetObject?table=block&id=0b6708bd-29a9-417a-bfa2-d99613dee330&cache=v2)
Mock by intercepting requests on the network level.
MSW는 네트워크 레벨에서 패킷을 가로채 Mokup 데이터를 보내주는 서비스 워커다. 이를 이용하면 1번과 2번의 단점을 모두 해결할 수 있다. 백엔드 개발자가 API에 세팅해두지 않아도 응답을 확인할 수 있고, 프론트엔드에서 실제 API를 호출하고 응답을 처리하는 프로세스대로 구현할 수가 있는 것이다.
패키지 설치 및 사용도 간단하여 복잡한 세팅없이 구현할 수 있다는 것도 큰 장점이다. React, Angular 및 NextJS, Storybook, Redux Saga, Karma에 대한 예제를 제공하고 있다.
브라우저 및 Jest에서 활성화할 수 있다.
MSW 사용하기
MSW 사용하기
MSW 설치
MSW 설치
패키지 설치
bash1$ npm install --save-dev msw 2# or 3$ yarn add -D msw
서비스 워커 생성
bash1$ npx msw init public/ --save
브라우저 환경에서 API 요청을 인터셉트하기 위한 파일을 생성해준다.
mockServiceWorker.js
라는 파일을 생성해준다.
MSW Resolver 생성
MSW Resolver 생성
1import type { ResponseResolver, RestRequest, RestContext } from 'msw';
2
3export const mockUser: ResponseResolver<RestRequest, RestContext> = (req, res, ctx): any => {
4 return res(
5 ctx.status(200), // 응답 Status Code
6 ctx.delay(1000), // 응답 지연시간
7 ctx.json({ // 응답 결과 데이터
8 id: 1,
9 email: 'treefeely@gmail.com',
10 name: 'Weezip',
11 })
12 );
13};
src/mocks/resolvers.ts
Resolver란 Mockup 데이터를 정의한 내용이다. express와 동일하게
req
,
res
,
ctx
객체를 활용할 수 있다.
ctx
객체를 활용하면 Status Code 및 Delay도 설정할 수 있다. 응답값을 조정하여 다양한 케이스에 대한 UI 테스트를 손쉽게 진행할 수 있다. 특히 delay를 설정하면 더이상 네트워크 탭에서 throttling을 조절하지 않아도 지연 테스트가 가능하다
MSW Handler 생성
MSW Handler 생성
1import { rest } from 'msw';
2import { mockHello } from './resolvers';
3
4export const handlers = [
5 // ...resolves
6 rest.get(`${process.env.ENDPOINT}/user`, mockHello),
7];
src/mocks/handlers.ts
REST API 주소와 함께 Mockup Resolver를 매칭하여
handlers
배열에 추가해준다. 브라우저에서 호출한 API 주소와 동일한 주소를 가지는 Resolver가 Handler에 매칭되어 있을 경우, Handler가 인터셉트하고 Resolve가 처리하여 서버대신 Mockup 데이터를 응답한다.
MSW 활성화 - Browser
MSW 활성화 - Browser
1import { setupWorker } from 'msw';
2import { handlers } from './handlers';
3
4const worker = setupWorker(...handlers);
5
6export default worker;
src/mocks/browser.ts
MSW에서 제공해주는
setupWorker
함수를 활용하여
worker
를 생성해준다. MSW의 그 W다.
Worker 등록
Worker 등록
1import worker from './mocks/browser';
2
3...
4if (process.env.NODE_ENV === 'development') {
5 worker.start({
6 onUnhandledRequest: 'bypass',
7 });
8}
9...
프로젝트의 최상단 파일에서
worker
를 실행시켜준다. 환경변수를 활용해서 개발환경에서만 실행한다.
MSW 호출
MSW 호출
![Console tab](https://treefeely.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fad9b6331-a1bf-4510-ab6e-afe732ede744%2F69dff21d-2b7c-4640-8a8b-a19242555732%2FUntitled.png%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Content-Sha256%3DUNSIGNED-PAYLOAD%26X-Amz-Credential%3DAKIAT73L2G45HZZMZUHI%252F20240730%252Fus-west-2%252Fs3%252Faws4_request%26X-Amz-Date%3D20240730T123504Z%26X-Amz-Expires%3D3600%26X-Amz-Signature%3D878b8ded10b34e610fa6a92085f0e9be0e77d9b6c3447c8a15d924362d852349%26X-Amz-SignedHeaders%3Dhost%26x-id%3DGetObject?table=block&id=d84f395d-0dd4-4f77-a5f0-33cba931d186&cache=v2)
Console tab
브라우저 콘솔 창에서
“[MSW] Mocking enabled.”라는 문구를 확인하면 정상적으로 MSW가 실행되고 있다는 뜻이다. 이후
handler
에 매핑한 API를 호출해보면
resolver
에서 정의한 데이터가 응답되고 있으며,
“[MSW] {time} {REST} {PATH} ({STATUS})”형식의 로그가 생기는 걸 확인할 수 있다.
![Network tab](https://treefeely.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fad9b6331-a1bf-4510-ab6e-afe732ede744%2F2ca7a51a-500b-42b5-b7f7-206305c24f49%2FUntitled.png%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Content-Sha256%3DUNSIGNED-PAYLOAD%26X-Amz-Credential%3DAKIAT73L2G45HZZMZUHI%252F20240730%252Fus-west-2%252Fs3%252Faws4_request%26X-Amz-Date%3D20240730T123504Z%26X-Amz-Expires%3D3600%26X-Amz-Signature%3De15c1cd5ade15b9269de20206d52f8fab5ab3e86d384fd42a5645a9795355da2%26X-Amz-SignedHeaders%3Dhost%26x-id%3DGetObject?table=block&id=65802a59-410c-4182-8515-d798d29f2f20&cache=v2)
Network tab
네트워크 탭에서도 Mockup 데이터로 응답하는 것을 볼 수 있다. 네트워크 패킷 자체를 인터셉트하여 응답을 바꿔서 보내주는 방식이기 때문이다.
MSW를 활용하면
MSW를 활용하면
이제 서버에 없는 API 주소로도 Mockup 데이터를 응답받을 수 있으며, 특정 API의 응답을 Mockup 데이터로 교체하여 응답받을 수 있다. 백엔드 개발자와 미리 데이터 형식을 정의해두기만 하면 된다. 이로 인해 프론트엔드 개발자는 API 개발에 대한 dependency에서 더 자유로워질 수 있으며, Mockup 데이터를 변경하여 다양한 상황에 대한 테스트를 손쉽게 진행할 수 있다.
네트워크 패킷을 인터셉트해서 동작하는 기본 원리를 이용하여 캐싱을 구현하는 등 다른 용도로도 충분히 사용할 수 있을 것 같다.
카카오의 도입기를 읽어보면 MSW 컨트롤러를 개발하여 UI 단에서 API 호출에 대한 다양한 응답 케이스를 재현할 수 있게 했다.
환경 구축도 간단하며, API dependency를 해소하고, 테스트를 손쉽게 하는 등 많은 효과를 볼 수 있다고 생각한다.
다만 worker를 띄워놓고 계속 작업하다보면, 어느 순간 worker가 동작하지 않고 사이트도 제대로 동작하지 않게 되는데 이럴 때는 Application 탭에서 Clear Site를 실행하면 된다. 아마 캐시가 많이 쌓이면서 그러지 않을까싶다.
Refer
Refer