[🐾JellyDiary] React 에서 MSW(MockServiceWorker) 이용하여 API 백엔드 Mocking 하기
이번 프로젝트를 진행하던 중 백엔드 개발 일정에 차질이 생겨 백엔드 서버가 구현되기 전에 프론트단 개발을 진행하는데에 어려움이 있어 목업 데이터를 생성해서 테스트 해보며 개발을 진행하고자 MSW 를 이번 프로젝트에 도입하게 되었다.
프로젝트는 React + Typescript + Vite 구성으로 진행 되었다.
1. MSW(Mock Service Worker) 란?
https://mswjs.io/docs/getting-started
MSW란 서비스워커를 사용하여 네트워크 요청을 가로채서 관찰하고 모의 응답을 사용할 수 있는 라이브러리이다.
프론트엔드에서 마냥 백엔드 API 개발만을 기다릴 수 없기 때문에 미리 결과 값을 만들어 놓고 호출하여 테스트 해볼 수 있는
자바스크립트 라이브러리라고 생각하면 된다.
이번 프로젝트에서 특히 유저 권한에 따라 보여줘야 하는 데이터 들이 달라지는 경우가 많기 때문에 사전에 적용해 보는 기간이 꼭 필요했다.
사용방법은 라이브러리 문서에 잘 나와있어 정리해보고자 한다.
2. 라이브러리 설치
npm install msw@latest --save-dev
3. 요청 핸들러 작성(Request handlers)
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/user', () => {
return HttpResponse.json({
id: 'c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3d',
firstName: 'John',
lastName: 'Maverick',
})
}),
]
handlers 파일을 생성하여 mock get API 를 작성해 줄 수있다. /user 엔드포인트로 가는 요청을 가로채 json 형식으로 반환해 줄 수 있다.
값이 많아지면 핸들러와, 리턴 값을 따로 파일로 관리할 수도 있다.
4. 요청 핸들러 관리
import userHandler from './userHandler';
import diaryHandler from './diaryHandler';
export const handlers = [...userHandler, ...diaryHandler];
핸들러가 많아지는 경우 관리가 어려워 핸들러만 따로 관리하는 파일을 하나 만들어 주었다.
5. 브라우저 MSW 셋팅(browser)
// src/mocks/browser.ts
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers.ts'
export const worker = setupWorker(...handlers)
리액트 웹 어플리케이션에 적용하려면 setupWorker을 사용하여 브라우저 셋팅을 해 주어야 한다.
6. 개발 환경에서만 msw 를 사용하도록 설정(Conditionally enable mocking)
// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './App'
async function enableMocking() {
if (process.env.NODE_ENV !== 'development') {
return
}
const { worker } = await import('./mocks/browser')
return worker.start()
}
enableMocking().then(() => {
ReactDOM.render(<App />, rootElement)
})
.env 의 환경 변수를 통해 개발환경에서만 목업 데이터로 보여주게 설정할 수 있다.
7. 확인
[MSW] Mocking enabled.
콘솔에서 'Mocking enabled' 를 확인할 수 있으면 설정이 완료 된 것이다.
8. REST API + MSW
GET, POST, DELETE 를 가진 기본 RESTful API 요청
// src/mocks/handlers.ts
import { http } from 'msw'
export const handlers = [
http.get('/posts', () => {
console.log('Captured a "GET /posts" request')
}),
http.post('/posts', () => {
console.log('Captured a "POST /posts" request')
}),
http.delete('/posts/:id', ({ params }) => {
console.log(`Captured a "DELETE /posts/${params.id}" request`)
}),
]
구조화 된 json 파일이 있다면 아래와 같이 불러오거나 인수를 받아 처리할 수 있다.
import { http, HttpResponse } from 'msw'
const allPosts = new Map()
export const handlers = [
http.get('/posts', () => { // HttpResponse를 통해 enable 결과 반환
return HttpResponse.json(Array.from(allPosts.values()))
}),
http.post('/posts', async ({ request }) => { // 'request'인수를 사용하여 요청
const newPost = await request.json()
allPosts.set(newPost.id, newPost)
return HttpResponse.json(newPost, { status: 201 })
}),
http.delete('/posts/:id', ({ params }) => { // 'params'를 사용하여 경로 처리
const { id } = params
const deletedPost = allPosts.get(id)
if (!deletedPost) {
return new HttpResponse(null, { status: 404 })
}
allPosts.delete(id)
return HttpResponse.json(deletedPost)
}),
]
쿠키를 받아 처리할 수도 있다.
http.get('/user', ({ cookies }) => {
const { session } = cookies
if (!session) {
return new HttpResponse(null, { status: 401 })
}
})
간단하게 json 파일을 작성하여 목킹을 할 수 있어서 굉장히 편리했다.
실제 서버단과 연결 하는 것과 차이는 있겠지만 충분히 미리 작업해 볼 수 있어서
개발에 도움이 되었다.