상세 컨텐츠

본문 제목

MSW를 이용해서 쉽고 깔끔하게 API Mocking 하자

TECH

by walkinpcm 2022. 5. 11. 21:28

본문

프론트엔드 개발을 하면서 백엔드 API를 연동하는 개발을 해본 사람이라면, 아마도 API 개발이 늦어져서 API 연동 작업이 지연되는 경험이 있을 거라고 생각합니다. API 개발이 지연되는 만큼 전체 과제 기간도 지연되면 참 좋겠지만, 현실적으로 과제 기간 지연은 쉽지 않고 나도 최대한 빠르게 개발을 완료해서 멋있는 개발자가 되고 싶습니다.

API 개발이 늦어질 때는 보통 API로 받아오는 응답을 Mocking해서 최대한 프론트엔드에서 먼저 개발을 해두고 API가 개발된 이후에 Mocking 코드를 제거하고 실제 API로 실행시켜 보면서 코드를 다듬습니다. 저는 처음에는 API를 연동하는 코드와 같은 파일에 Mocking 데이터들을 하드코딩하고 실제 API 연동 코드는 주석 처리해서 사용했습니다. 그런데, 이렇게하면 API 개발 완료 이후에 하드코딩한 Mocking 데이터를 삭제하고 API 연동 코드는 주석을 해제한 뒤에 실제 API 코드로도 잘 동작하는데 다시 확인해야하는 번거로움이 있습니다.

 

그러던 중에 아주 매력적인 라이브러리를 만났습니다.

MSW. ( Mock Service Worker )

MSW는 API를 쉽고 깔끔하게 Mocking 할 수 있게 도와주는 라이브러리입니다. 도입은 30분만에 빠르고 가볍게 할 수 있는데, 그 효과는 정말 뛰어납니다. 개발 시간을 효과적으로 줄여주고 개발 경험을 크게 향상 시켜줍니다.

 

MSW의 가장 큰 특징과 장점은 Service Worker에서 API를 Mocking 하는 것입니다.

API 요청이 서버로 전달되는 순서를 간략하게 따져보자면 웹어플리케이션 코드에서 axios와 같은 라이브러리로 API 요청을 보내고 이 요청은 브라우저에서 Service Worker를 거친 다음에 네트워크로 나가게 됩니다.

MSW는 이 중에서 요청의 순서 중 마지막인 Service Worker에서 요청을 가로챈 뒤 Mocking 데이터로 응답을 반환해버립니다. (네트워크로 요청이 나가지 않습니다.)

그래서, 웹어플리케이션 코드를 어떤 언어로, 어떤 프레임워크로, 어떤 라이브러리로 작성하든 & 어떤 라이브러리로 HTTP 요청을 보내든 상관없습니다. 의존성이 전혀 없고, Mocking 코드 또한 별도의 파일로 관리됩니다. 즉, 웹어플리케이션 코드에 Mocking 데이터가 추가 되지 않습니다. 웹어플리케이션 코드는 처음부터 실제 API를 호출하듯이 작성할 수 있습니다. 실제 API 개발 이후에 웹어플리케이션 코드를 추가적으로 수정할 필요가 없습니다.

 

효과는 아주 크지만 도입은 아주 간단합니다. 공식 문서에도 도입 방법이 아주 간단하고 친절하게 안내 되어 있습니다.

 

MSW 도입 방법

(1) msw 라이브러리 설치

msw 라이브러리를 devDependency로 설치합니다.

yarn add msw --dev

 

(2) handler 작성

어떤 endpoint를 가진 API를 어떤 응답으로 Mocking할지 정의하는 곳이 handler입니다.

프로젝트의 루트 디렉토리 또는 `src`폴더 하위에 `mocks` 폴더를 만들고 그 하위에 `handlers.js`파일을 만들어서 다양한 handler를 정의합니다. (폴더명이나 파일명은 원하는 이름으로 변경해도 됩니다. 다른 곳에서 참조할 때 경로만 잘 명시해주면 됩니다.)

handlers.js 내에서 아래와 같이 API Mocking 코드를 작성합니다.

/** src/mocks/handlers.js */

import { rest } from 'msw'

export const handlers = [
  // Handles a GET /user request
  rest.get('/user', (req, res, ctx) => {
    return res(
      ctx.status(200),
      ctx.json({
        // Mocking할 Data를 정의합니다. API 스펙에서 응답 예시를 복사해서 넣어주면 됩니다.
        // 아래는 예시입니다.
        name: 'walkinpcm',
        blog: 'blog.walkinpcm.com',
      }),
    )
  }),
  // 다른 handler도 배열 안에 정의하면 됩니다.
]

여러 handler를 정의하여 사용하다가 더이상 Mocking이 필요없는 API는 배열에서 제거해주거나 주석처리하면 됩니다.

 

(3) Service Worker 셋업

Service Worker를 사용하기 위해서 worker 코드를 작성해줘야하는데, MSW에서는 이 코드를 개발자가 직접 짜게하지 않고 라이브러리에서 제공해줍니다. 제공해주는 코드를 적용하기 위해서 아래 명령어를 실행합니다.
아래 명령어를 실행하면 public/mockServiceWorker.js 가 생성되며 package.json 파일에 msw.workerDirectory가 추가됩니다. package.json에 정보를 설정하는 이유는, 추후에 msw가 업데이트 되면서 mockServiceWorker 스크립트가 변경되면 이 변경사항을 자동으로 로컬 파일에 반영해주시 위함이라고 합니다. (worker 코드를 직접 작성하지 않게 해주면서 코드가 갱신되어도 갱신까지 알아서 해주는 편리함)

여기서 `public/`은 웹어플리케이션의 Public Directory입니다. 웹어플리케이션을 호스팅할 때 정적 리소스들을 호스팅하는 폴더에 mockServiceWorker.js 파일도 함께 호스팅 되어야 합니다. 저는 CRA 기반의 프로젝트라서 `public/` 경로를 넣었습니다.

npx msw init public/ --save

 

(4) worker 설정

worker에 핸들러를 등록해줍니다. `handlers.js`와 동일한 위치에 `browser.js`파일을 생성하고 아래 내용을 입력합니다.

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

// 정의했던 handler들을 worker에 등록합니다.
export const worker = setupWorker(...handlers)

 

(5) worker 실행

마지막으로 웹어플리케이션이 실행될 때 Service Worker도 함께 실행해줍니다.

넣어줘야 하는 코드는 아래에서 if문 입니다. 각자 프로젝트에서 웹어플리케이션의 최초 실행 코드에 if문 코드를 입력하면 됩니다.

저는 CRA 기반 프로젝트라서 `src/index.js`에 작성하였습니다.

/** src/index.js */
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

// 웹어플리케이션에서 가장 먼저 실행되는 코드에 아래 if문을 추가합니다.
if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./mocks/browser')
  worker.start()
}

ReactDOM.render(<App />, document.getElementById('root'))

여기서는 개발환경에서만 msw가 동작하도록 제한합니다. 당연하게도 운영환경에서는 실제 API로 요청을 보내야하니깐요.

 

 

여기까지가 MSW를 도입하는 방법이었습니다. 실제로 해보면 잘 모르고 따라해도 30분이면 합니다. 아주 적은 시간인데, 실제로 업무할 때 사용해보면 너무 큰 만족을 느낄 수 있습니다.

이렇게 개발경험을 향상 시켜주는 좋은 라이브러리는 널리널리 퍼뜨려야겠습니다.

관련글 더보기

댓글 영역