[MSW] MSW 로 API mocking 하여 데이터 통신하기

Gyuhan Park·2023년 8월 8일
3

nextjs

목록 보기
3/10
post-thumbnail

💭 TMI

프론트엔드 개발을 하다보면 와이어프레임 기다리고, 디자인 기다리고, 서버 API 개발까지 기다리다보면 난 개발 언제해???? 소리가 나온다.

카카오 FE 개발자 분도 그걸 느꼈는 지 가상의 서버 만드는 기술을 블로그에 적어주셨다. 우연히 그걸 봤는데 나의 고민이 담긴 글과 함께 해결책을 제시해주셨다.

그건 바로 MSW

MSW 란?

MSW : Mocking Service Worker

단어는 어려운데 가짜 서버와 API통신을 테스트하는 것이다. 가짜 서버를 목서버(mock server) 라고 하는데 백엔드 API가 나오기 전에 목서버와 API 통신을 하여 나중에 백엔드 API를 붙일 때 fetch 함수만 변경해주면 된다 !!!

그래서 다음 이미지와 같이 API가 나올때까지 기다리는 시간을 줄이고 전체 개발시간도 줄일 수 있다.

✅ 환경 설정

npm install --save-dev msw
npx msw init ./public --save

위 명령어를 실행하면 ./public/mockServiceWorker.js 파일이 생성된다.

✅ mock server 생성

mocks 디렉토리를 생성하고 browser.js, handler.js 파일을 생성한다.

// src/mocks/browser.js
import { setupWorker } from 'msw';
import handlers from './handler';

export const worker = setupWorker(...handlers);
// src/mocks/handler.js
const { rest } = require('msw');

const handlers = [
  rest.get('/api/product', (req, res, ctx) => {
    return res(
      ctx.status(200),
      ctx.delay(2000),
      ctx.json({
        result: [{ name: 'Park' }]
      })
    );
  })
];

export default handlers;

entry 파일에 다음과 같은 코드를 작성한다.
next에서는 react와 동작방식이 달라 [MSW] Failed to execute setupWorker in a non-browser environment. 라는 오류가 발생하므로 분기처리를 해줘야 한다.

// _app.tsx
if (process.env.NODE_ENV === 'development') {
  (async () => {
    const { worker } = await import('../src/mocks/browser');
    worker.start();
  })();
}

✅ API 테스트용 호출

fetch('/api/product').then((res) => console.log(res));

🔥 결론

오호라 되게 신기하다 말되나? 이제는 서버없이도 해낼 수 있다 !!!
API 명세가 나오더라도 자주 바뀌는데 목서버를 통해 값이 제대로 넘어오는 지 테스트를 해보고 마지막에 바꿀 수 있어서 좋은 것 같당

🔍 MSW 2.0.0

잠시 한눈판 사이에 2 버전이 나왔다!
23년 8월에 해커톤 때 적용했던 MSW 버전이 1.2.3 인데 앞자리가 바뀐 2버전이 나온 지금은 24년 1월...5개월만에 나왔다.
오류없이 1.2.3 을 설치하려 했지만 typescript 버전을 5.2.2 로 올려서 5.0.x 까지만 호환되는 1 버전은 사용하지 못한다. 다시 공부해보자.

💭 TMI (2)

실제 서버는 내려가있는 상태였고, 프로젝트 구조가 API 종속적 이였다. 상태를 hooks로 관리하는 것이 아니라 Mobx의 Repository, Model 구조에 따라 API로 불러온 데이터를 렌더링한다. 따라서 더미데이터로 동작시키기에 어려움 이 있었고, 데이터가 없을 때는 화면에 아무것도 보이지 않아 컴포넌트 구조를 파악하기 어려웠다. 하지만 실제 서버가 올라올 때까지 기다릴 수 없었다. 그래서 msw를 도입하기로 결정하였다.

라이브러리 적용 및 유지보수가 어려워 전체 패키지 버전업을 진행하였고, 마이그레이션 후 msw 2.0.13 버전을 설치하여 API mocking을 진행하였다.
실제 서버가 구동되더라도 추후에 서버가 내려갔을 때 프론트엔드 코드 유지보수에 도움이 될 거라고 생각하여 끝까지 개발할 예정이다.

✅ msw 환경 세팅

위에서 설명한 것처럼 아래 명령어를 실행하여 ./mockServiceWorker.js 생성

npm install --save-dev msw
npx msw init ./public --save

이전과 다르게 browser과 handler를 ts 파일로 설정하였는데 dynamic import 시
const { worker } = await import('./mocks/browser'); 문장에서 암시적으로 any 타입을 반환한다고 오류가 발생하여 수정하였다.

browser.ts

import { setupWorker } from 'msw/browser';
import handlers from './handler';

export const worker = setupWorker(...handlers);

handler.ts
1 버전과 다르게 HttpResponse 객체 모듈을 사용해 응답을 반환한다

import { http, HttpResponse } from 'msw';

const handlers = [
  http.get('/api/test', () => {
    return HttpResponse.json({ id: 'abc', name: 'Gyu' });
  }),
];

export default handlers;

index.tsx

async function enableMocking() {
  if (process.env.NODE_ENV !== 'development') {
    return;
  }

  const { worker } = await import('./mocks/browser');
  return worker.start();
}

enableMocking().then(() => {
  render(
    <React.StrictMode>
      ...
    </React.StrictMode>,
    document.getElementById('root'),
  );
});

✅ POST request mocking

보통 GET 요청만 mocking해서 컴포넌트 렌더링 되는지 테스트하는 용도로 사용했는데 POST 요청을 mocking 해보자.
mocking을 많이하다보니 한 파일에서 보기 복잡해서 카테고리별로 handler 파일을 나누고, 중복되는 mock data 또한 따로 분리하였다.

mocks/handler.ts

const handlers = [
  http.get('/api/v1/posts', getAllPostHandler),
  http.post('/api/v1/posts', createPostHandler),
  ...
];

mocks/postHandler.ts
작성한 게시글의 데이터를 body로 넘겨 DB에 저장한다.
1 버전에서의 request.body 대신 await request.json() 을 통해 request body를 얻을 수 있다.
기존의 mock data인 contentList에 넣으면 GET API 에서도 불러와지는 것을 확인할 수 있다. 대신 새로고침하면 추가한 데이터는 다시 사라진다.

import { contentList } from './mockData';

export const createPostHandler = async ({ request }: { request: Request }) => {
  const body: Post.CreateRequestDto = await request.json();

  contentList.push({
    title: body.title,
    content: body.content,
   	...
  });

  return HttpResponse.json(...)
};

https://tech.kakao.com/2021/09/29/mocking-fe/
https://mswjs.io/docs/migrations/1.x-to-2.x/
https://velog.io/@hamsoo159/React-MSW-2.0%EC%9D%84-%EC%95%84%EC%8B%9C%EB%82%98%EC%9A%94

profile
단단한 프론트엔드 개발자가 되고 싶은

0개의 댓글