개발 관련/React

[MSW] FE를 위한 MSW를 활용한 API Mocking (세팅, 사용법) with NextJS

Hago하고 2023. 8. 20. 17:48
반응형

최근에 과제를 하면서 새로운 경험을 하게 되어 이를 글로 정리해놓으려고 한다.

과제에는 목업용 json 파일이 포함되어 있었고, 이를 활용해 화면에 data를 뿌려줘야 했었다.

 

어떤 방식을 쓸까 고민하던 와중, 동료 개발자가 이전에 MSW를 활용하여 백엔드 api가 없는 상황에서 개발을 하던 것이 생각나서 이를 사용해보기로 결정했다.

 

MSW 라이브러리 설치

$ npm install --D msw

위의 커맨드로 msw를 설치해준다

 

MSW 기본 세팅

$ npx msw init public/

해당 명령어를 통해 기반 코드를 자동으로 생성할 수 있다.

여기서 public/은 정적 리소스 코드를 넣어두는 폴더로, Create React App이나 Next, Vue를 활용하면 자동으로 생성되는데 이를 바로 활용할 수 있다.

 

생성된 파일은 그대로 냅두고 진행하면 된다.

Mock 폴더 생성 및 서버 세팅

기본 세팅이 끝났다면 이제 Mock 데이터가 돌아가게 하는 서버를 만들어줘야 할 차례이다.

Mock 서버에는 두 가지 종류가 존재하는데 바로 node(백)browser(프론트)다.

 

여기서 중요한 점은 Next는 node와 browser 모두 세팅해주어야 합니다.

 

다른 곳은 확인해봐야 알겠지만, 현재 사용하는 Next의 특성상 server side가 먼저 렌더링 된 후에 client side가 렌더링 되기 때문에,

'프론트만 사용하니 node는 넘어가야지' 하는 순간 에러를 면치 못할 것입니다.

 

// src/mocks/node.ts

import { setupServer } from 'msw/node';
import { handlers } from './handlers';

// 실제로는 node 서버를 사용하지 않지만 넥스트 구조상 server side가 먼저 렌더링 된 후에 client side가 실행되기 때문에
// node 환경에 대한 설정이 필요

export const server = setupServer(...handlers);

msw/node에서 setupServer를 불러와 export해줍니다.

// src/mocks/browser.ts

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

export const worker = setupWorker(...handlers)

browser에서는 msw에서 불러온 setupWorker를 통해 붙여줍니다.

 

여기서 handlers를 볼 수 있는데, 이 부분이 우리가 통신을 할 때 응답을 보내주는 역할을 할 것입니다.

이어서 handlers를 세팅하러 가보죠.

 

Handler 세팅

// src/mocks/handlers/something.ts

import { rest } from 'msw'
import page1 from './json/page_1.json'
import page2 from './json/page_2.json'
import page3 from './json/page_3.json'
import page4 from './json/page_4.json'
import page5 from './json/page_5.json'

const pageData = [
	page1,
	page2,
	page3,
	page4,
	page5,
]

export const somethingHandlers = [
	// GET '/api/something'로 요청 시 각 page에 맞는 응답을 전달
	rest.get('/api/something',(req, res, ctx) => {
        // 여기에서는 page를 parameter로 받아 해당 페이지의 데이터를 뽑아주기 위해 아래처럼 사용했습니다.
        // req에서 들어온 요청의 url을 받아올 수 있고, searchParams.get을 통해 원하는 파라미터를 받아올 수 있습니다.
        // 만약 page가 존재하지 않을 경우 자동으로 1페이지로 설정합니다.
			const page = req.url.searchParams.get('page') ?? 1

		// res를 리턴하며 해당 응답 안에 컨텍스트를 json 형태로 담아 보냅니다.
        // 여기서는 data 안에 pageData를 정리해서 보내도록 하였습니다.
        // 기본적으로 searchParams.get()으로 불러온 값은 string 타입이기 때문에 형번환도 진행하였습니다.
			return res(
				ctx.json({
					data: pageData[Number(page) - 1],
				}),
			)
		},
	),
]

handlers라는 폴더 내에 생성한 something 핸들러입니다.

원하는 api를 호출하면 msw가 가로채어 이 곳에서 응답을 보냅니다.

이외에도 handlers폴더 내에 도메인별로 분리하여 handler 세팅을 해준다면 좋겠죠?

 

// src/mocks/handlers/index.ts

import {somethingHandlers} from '@/mocks/handlers/something';

export const handlers = [
    ...Object.values(somethingHandlers)
    //, ...Object.values(anotherHandlers) 의 형식으로 다른 핸들러를 추가해주시면 됩니다.
]

handlers/index.ts에서는 각 핸들러들을 하나로 묶어 반환해주는 역할을 할 것입니다.

이렇게 되면 이제 기본적인 세팅은 끝납니다.

 

_app.tsx 세팅

_app.tsx는 기본적으로 모든 페이지의 기초에 해당하는 곳으로, 여기에서 mock 서버를 열어줄 수 있도록 합니다.

세팅은 아래와 같습니다.

 

export default function App({ Component, pageProps }: AppProps) {
	//process에 browser가 없다면 server라는 뜻입니다.
    // 해당 여부에 따라 백엔드 서버를 켜고 끕니다.
  const isServer = !process.browser;

	// NODE_ENV가 development일 경우 해당 mock 서버를 실행시켜줍니다.
  if (process.env.NODE_ENV === 'development') {
    if (isServer) {
      (async () => {
        const { server } = await import('@/mocks/node');
        server.listen();
      })();
    } else {
    // browser에서 worker를 가져와 start 해줍니다.
      (async () => {
        const { worker } = await import('@/mocks/browser');
        worker.start();
      })();
    }
  }

  return (
      <Component {...pageProps} />
  )
}

 

확인방법

자, 이제 직접 npm run dev를 하여 테스트를 해봅시다.

localhost:3000으로 들어가서 콘솔을 보면 해당 mock 서버가 동작하는지 확인할 수 있습니다.

[MSW] Mocking enabled. 라고 표시가 되며 정상적으로 작동하는 것을 확인할 수 있습니다.

이제 fetch를 통해 해당 데이터를 부르면 정상적으로 확인이 가능합니다.

 

 


MSW 동작 원리

 

서비스 워커는 설치된 순간, 모든 요청을 Service Worker가 가로채게 됩니다.

가로챈 요청을 MSW로 복사하여 우리가 handler에 지정해둔 응답을 반환하게 됩니다.

 

이를 통해 실제 백엔드 서버의 존재 여부와 관계 없이 개발할 수 있게 됩니다.

(출처 : 카카오 테크 페이지)


MSW에 대한 개인적인 생각

회사에서 작업을 하게되면 주로 백엔드에 의존적인 경험을 많이 하게 됩니다. api가 완성되지 않아 프론트에서는 화면만 그려놓고 대기하는 순간이 길어지기도 하구요.

 

물론, 그런 상황이라면 즐겁게 기다리면서 강의를 보거나, 다른 이슈의 처리를 하는 것도 좋은 방법이지만, 만약 그럴 시간이 없는 경우라면? 프로젝트의 시간이 얼마 남지 않았거나, 빠르게 해결해야되는 운영 이슈라면?

 

그럴 경우에는 마냥 손가락만 빨며 기다리고 있기에는 부담감이 너무 크다고 생각합니다. 저도 이러한 상황을 겪은 적이 있었고, 그 때는 MSW를 써볼 생각도 하지 못했기 때문에 결국 야근을 해서 시간을 맞출 수 있었죠.

 

이러한 상황에서 MSW는 매우 좋은 선택지라고 생각합니다.

 

백엔드 분깨 여쭈어보고 테스트에 필요한 mock json을 미리 만들어두고, api 세팅을 똑같이 해둔 뒤 작업을 해놓는다면,

백엔드가 완성되기 전에도 얼마든지 작업을 끝내놓을 수 있다는 점은 참으로 매력적입니다.

 

 

반응형