React에서 사용하는 MSW

이지원·2024년 5월 11일
0
post-thumbnail

오늘은 msw에 대해서 작성해볼겁니다.

msw란?

Mock Service Worker의약자로
서버향의 네트워크 요청을 가로채서 모의 응답(Mocked response)을 보내주는 역할을 합니다.

사용시 이점

  1. 프론트엔드에서 모의 응답을 작성하기 매우 편하고 단위테스트를 적용하기에도 너무 좋다는 것을 알았습니다.
  2. 백엔드에 상관없이 프로토타입 출력문을 보여줄 수 있다.

사실 2번은 매우 중요한 장점이라고 생각합니다.
신입 시절 있있던 문제입니다.

기획자님: 지원씨 이 부분 어느정도 남았어요?
나: 아 그부분은 아직 백엔드 api가 준비되지 않아서요.
잘 모르겠습니다. 확인 후 다시 말씀드리겠습니다.

이런식으로 백엔드 api를 기다리면서 비개발 직군분들과 소통에 어려움을 주고 말았습니다..
(이런 바보)
지금 생각해보면 당연히 저렇게 의사소통 했으면 안됐는데,,(머리를 탁)

프로젝트의 개발 단계는 아래와 같습니다.

기획 -> 디자인 -> 백/프론트 개발 -> 테스트 -> 출시

하지만 모든 프로젝트가 이렇게 원만하게 순서가 진행되지 않죠
개발을 하다가 여러가지 문제점도 있기도하고 여러가지 변수가 존재합니다.
하지만 백/프론트가 동시에 개발을 시작하게 되면
프론트 입장에서 dummy데이터로 화면을 보여준다음 백엔드 api가 완성이 될 때
dummy데이터를 api로 교체하는 작업도 일일이 하다보면 굉장히 번거롭져
그래서 msw를 이용하면 좋은 것 같습니다.

설치

여기서 버전을 주의해야 하는데 저는 최신버전은 작업시에 문제가 발생해서 0.35.0 버전으로 설치했습니다.

npm i msw@0.35.0

폴더 구조

📦mocks
┣ 📂api - mock api 담당
┃ ┣ 📜index.js - index
┃ ┗ 📜reservation.js - api 기능 함수
┣ 📜browser.js - msw를 셋팅하기 위한 파일
┣ 📜handler.js - msw handler
┗ 📜index.js - index파일로 msw를 셋팅하기 위한 init 파일

이렇게 구성을 했다.

실행환경은 typscript와 vite를 사용했다.

browser.js

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

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

mocks/index.js

async function initMocks() {
  if (typeof window === 'undefined') {
    // const { server } = await import('./server.js');
    // server.listen();
  } else {
    const { worker } = await import('./browser.js');
    worker.start();
  }
}

export default initMocks;

여기서 browser.js와 index.js는 사실 기본적인 셋팅은 다 비슷하다 하지만 여기서
handler.js파일은 좀 다르게 수정했는데

handler.js

import { rest } from 'msw';
import { reservationAPIList } from './api';

const baseUrl = 'https://jsonplaceholder.typicode.com';

// 공통 요청 처리 함수
async function handleRequest(req, res, ctx, mockFunction) {
 try {
   const response = await ctx.fetch(req);
   /**
    * 만약 baseUrl의 end point로 api를 호출 했는데
     아직 개발되지 않은 api인 경우 catch문에 mockFunction으로 넘어가게끔
     throw 강제 에러를 던져준다.
    * 
   */
   if (response.status >= 400) {
     throw new Error('Bad response');
   }
   return res(ctx.status(response.status), ctx.json(await response.json()));
 } catch (error) {
   console.log('Error:', error.message);
   return mockFunction(req, res, ctx);
 }
}

/**
*
* @returns 최종적으로 api 라우터와 응답값을 핸들하는 함수입니다.
*/
export function handlers() {
 return [
   rest.get(`${baseUrl}/time`, (req, res, ctx) =>
     handleRequest(req, res, ctx, reservationAPIList.getTimes)
   ),
   rest.get(`${baseUrl}/todos`, (req, res, ctx) =>
     handleRequest(req, res, ctx, reservationAPIList.getTodos)
   ),
 ];
}

여기서 중요하게 볼 코드는 handleRequest함수인데
개발 의도는 이렇다.
백엔드 api가 모두 개발되기전에 baseUrl로 api를 이용할텐데 프론트엔드 화면에서는 우선 개발 진행 상황을 다른 분들에게 보여줘야 개발팀의 상황을 공유할 수 있다고 생각이 들었다.
그래서 백엔드 개발자 분들과 사전에 데이터를 어떤 형식으로 주고 받을지,endpoint를 미리 지정해서
만약 백엔드 api가 실제로 개발되었으면 해당 api를 호출하고, 그게 아니라면
내가 만든 mock api를 호출하는 함수이다.

main.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import '@/styles/global.scss';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RootRouter } from './router/RootRouter';
import initMocks from '@/mocks/index.js';

/**
* 개발환경에서만 실행해줍니다.
*/
if (import.meta.env.DEV) {
 await initMocks();
}

const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')!).render(
 <React.StrictMode>
   <QueryClientProvider client={queryClient}>
     <RootRouter />
   </QueryClientProvider>
 </React.StrictMode>
);

이렇게 실행해보면 아래와같이 service worker에서 데이터를 응답하는 것을 볼 수 있다

profile
안녕하세요 피드백은 언제나환영입니다.

0개의 댓글