MSW API 모킹 (feat. 2.0)

송인재·2023년 11월 12일
5
post-thumbnail

개요

API 모킹이라는게 뭘까?
API 모킹을 알아보기 전에, 프론트엔드백엔드개발 방식에 대해 생각해봐야한다.

백엔드에서 API가 완성되기 전까지 프론트엔드UI를 그리는 작업밖에 하지 못한다.
이로 인해 개발 시간에 공백이 생긴다.

물론, 다른 방법이 존재하긴한다.
바로 머릿속으로 그리는 방법이다!
어떠한 API가 주어질지 상상하고 작업하는 방식이다.
하지만 해당 방법은 실제 API가 만들어지기 전까지 실제로 작동시키지 못한다.

그렇다면 어떻게 해야할까?
바로 우리가 보내는 API를 가로채서 우리가 그에 응당하는 데이터를 보내주면 된다.
이것이 바로 API 모킹이다.
API 모킹을 사용한다면 백엔드와 프론트엔드가 비동기로 개발이 가능하다.
이 API 모킹을 가능하게 해주는 것이 MSW이다.


MSW 설치

msw를 배포시에는 사용하지 않을 것이기 때문에 다음과 같이 설치한다.
npm i -D msw


Service Worker 등록

API를 네트워크 선에서 차단하기 위해, 서비스 워커를 등록해야한다.
해당 작업을 친절하게도, MSW에서 제공해준다.
npx msw init <정적 저장 폴더 위치>

대부분 public 폴더에 정적인 파일들을 저장하기에,
다음과 같은 명령어를 작성하면 된다.
npx msw init public

다음과 같이 작성하면 public폴더를 유지시킬지 유무를 묻는데,
특별한 이유가 없다면 Y를 입력하면 된다.
이것이 귀찮다면 다음과 같이 작성하면 된다.
npx msw init public --save


Worker 설정

이제 우리가 작업할 API들을 한 번에 관리해줄 워커를 설정해주자.
src 폴더 안에 mock 폴더를 만들어 다음과 같은 파일을 작성하자.

// src/mocks/browser.js
import { setupWorker } from 'msw/browser'
import { handler } from './handlers' // 이 부분은 추후에 작성
 
export const worker = setupWorker(...handlers)

조건부 워커 실행

이제 마지막 설정 작업인데,
우리가 API 모킹을 개발 환경에서만 진행을 할 것이기 때문에,
개발 환경에서만 워커가 작동해야한다.

이를 위해 다음과 같이 최상단 index.ts(.js)파일에 다음의 코드를
상단에 추가해주자.

// src/main.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { worker } from './mocks/broswer'; // import하기!!

// 아래 조건문만 추가하면 된다!!!
if (process.env.NODE_ENV === 'development') {
  worker.start();
}

// 아래는 기존 제공되는 파일들이라 수정할 필요가 없다
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
  </React.StrictMode>,
)

다음과 같이 작성한다면 .env 파일이 development일때만
워커가 실행되도록 할 수 있다.

// env
NODE_ENV = development

API 등록

이제 본격적으로 워커에 등록해줄 API를 작성해보자.
msw가 2버전으로 올라가면서 rest가 없어지고 http로 대체되었다.

요청 핸들러

http[method](predicate, resolver)

http 에 모킹할 API들에 대하여 작성하면 된다.
method 에는 get, post, delete와 같은 메소드를,
predicicate 에는 해당 API의 경로,
resolver 에는 실행할 함수를 입력하면 된다.

// 예시
http.post('/post/:postId', async ({ request }) => {
  // 로직 작성
}

그리고 내가 실행하는 로직이 아닌,
외부 서비스에 대하여 API를 가로채기 위해서는 아래와 같이 절대 경로를 작성하면 된다.

http.post('https://example.com/resource', async ({ request }) => {
  // 로직 작성
}

http에는 다양한 값들이 들어있는데,
그 중에서 아래와 같이, request, params, cookies를 읽을 수 있다.

http.post('/post/:postId', async ({ request, params, cookies }) => {
  // 로직 작성
  const data = await request.json();
  const { postId } = params;
  const { session } = cookies;
}

응답 해석기

응답은 text, json, xml, formData, blob, url등 다양하게 반환이 가능하다.

// json 반환
return HttpResponse.json(newPost, { status: 201 })

// text 반환
return HttpResponse.text('Hello world!')

// xml 반환
return HttpResponse.xml(`
<post>
  <id>abc-123</id>
  <title>Modern Testing Practices</title>
</post>
`)

// formData 반환
return HttpResponse.formData(form)

// arrayBuffer 반환
return HttpResponse.arrayBuffer(buffer, {
  headers: {
    'Content-Type': 'application/octet-stream',
  },
})

// null 반환
return new HttpResponse(null, { status: 404 }) // new 필수!!

그리고 응답에 Header 에 다양한 속성들을 담아줄 수 있다.

// 응답 타입
return new HttpResponse('Not found', {
  status: 404,
  headers: {
    'Content-Type': 'text/plain',
  },
})

// 쿠키
return new HttpResponse(null, {
  status: 200,
  headers: {
  'Set-Cookie': `token=1`,
  },
});

예시

백문이불어일견.
직접 작성한 회원가입과 로그인 API를 모킹한 코드를 살펴보자!

// src/mocks/handlers.js
import { HttpResponse, http } from 'msw';

const members = [];

export const handler = [
  
  // 회원가입 API
  http.post('/api/join', async ({ request }) => {
    const data = await request.json();

    members.push(data);

    return new HttpResponse(null, { status: 201 });
  }),

  // 로그인 API
  http.post('/api/login', async ({ request }) => {
    const data = await request.json():

    for (const member of members) {
      if (data.email === member.email && data.password === member.password) {
        return new HttpResponse(null, {
          status: 200,
          headers: {
            'Set-Cookie': `token=1`,
          },
        });
      }
    }

    return new HttpResponse(null, { status: 404 });
  }),
];

마무리

  • MSW를 이용하면 프론트엔드와 백엔드의 비동기 개발이 가능하다.
  • 사전에 백엔드에게 API 명세서에 관하여 논의를 하며, API에 관하여 미리 회의할 수 있어, 서로가 생각하는 API의 간극을 좁힐 수 있다.
  • 다만 배우는 시간과, 처음 설정하는 것에 시간이 소요된다는 단점이 있지만, 매우 급한 경우가 아니라면 배워보고 적용하는 것을 추천한다.

틀린 점이 있다면 말씀 부탁드립니다🙏
개발자분들에게 많은 도움이 되었으면 좋겠습니다:)

profile
꿈을 꾸고 도전하기🌟

0개의 댓글