지금까지 프로젝트를 진행할 때 항상 프론트는 나 한명이었고, 그에 따라서 진행해야 하는 부분에 대해 고려사항이 많았다. 기본적인 프로젝트 아키텍처를 어떻게 가져가야 할지, 기술스택은 어떤걸 쓸지, 공통 컴포넌트는 어떤걸로 할지, 등등 나 또한 전체적인 맥락을 가져가는 부분에 있어서 늘 레벨업을 꿈꾸다 보니 나의 프로젝트 접근을 달리 해야 해서 정말 내가 잘하고 있는지 ? 혹시나 이러한 접근이 타인이 볼 때 수정해야 부분이 많아 보일지 ?
늘 완성은 잘 되었지만, 사람들끼리 일하는 협업 부분에 있어서 늘 걱정이 앞섰다. 내가 가져가는 툴들이 다른이들이 볼 때 맞지 않는 부분들이 많을 것이고 다른 이들이 가져가는 방식이 훨씬 효과적이라면 내가 그에 따라가는 식의 수정이 있을 것 같기 때문이다.
서론이 길었다.
지금까지의 프로젝트에서 API 관련한 부분은 늘 명세서에 맞게끔 잘 전달이 되서 MSW 도입에 대해서 생각치도 않고 있었지만 내가 앞으로 실무에서 작업을 할 때 프론트팀끼리 정한 템플릿 양식, 공통 컴포넌트 제작 등등 분업화에 따른 빠른 일처리로 모킹된 데이터를 다뤄야 할 일이 생길 것 같아 미리미리 대처하려고 한다!
본격적으로
MSW를 설정하기 전,MSW가 무엇이고 어떤 방식으로 동작하는지 간략하게만 짚고 넘어가보자
MSW는 Mock Service Worker. 여기서 Mock은 ‘모의’, ‘모조’, ‘가짜’ 라는 뜻이다.
MSW는 실제 API 요청이 발생하면, 이 요청을 가로채서 미리 준비해 뒀던 Mock data로 응답해준다.
MSW를 사용하면 Mock Server를 따로 구축하지 않아도 API를 Mocking할 수 있어서 효율성이 증대된다.
아래 그림은 Mock Service Worker의 request가 어떤 식으로 흘러가는지 큰 그림으로 표현한 것이다. 공식문서를 참조했다.

브라우저에서 요청을 보낸다.
Service Worker는 요청을 받고, 해당 요청을 복제한다. 복제한 요청을 MSW에게 보낸다.
MSW는 요청과 일치하는 목업을 생성한다.
MSW는 모킹한 응답을 Service Worker에게 보낸다.
Service Worker가 모킹된 응답을 브라우저에게 보내고, 브라우저가 최종적으로 이 응답을 받는다.
MSW를 설치하고, public 폴더에 mockServiceWorker 파일을 생성한다.
// install MSW (package.json dependency에 기록하는 습관을 가지자)
npm install msw --save-dev
// create mockServiceWorker file in public folder
npx msw init public/ --save```
Handler 함수들을 만들어서 API를 모킹한다.
REST API 방식, GraphQL API 방식 중에 선택해서 API를 모킹할 수 있다.
현재 적용하려는 프로젝트는 REST API 방식이어서 msw에서 rest를 import 한 후 사용한다.
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';
export const handlers = [
http.post('/api/login', () => {
console.log('로그인');
return HttpResponse.json(User[1], {
headers: {
'Set-Cookie': 'connect.sid=msw-cookie;HttpOnly;Path=/',
},
});
}),
http.post('/api/logout', () => {
console.log('로그아웃');
return new HttpResponse(null, {
headers: {
'Set-Cookie': 'connect.sid=;HttpOnly;Path=/;Max-Age=0',
},
});
}),
];
현재 app 라우터 구동방식으로는 MSW 도입에 에러가 많아서 별도의 node 서버를 만들어서 작동시킨다.
// src/mocks/http.ts
import { createMiddleware } from '@mswjs/http-middleware';
import express from 'express';
import cors from 'cors';
import { handlers } from './handlers';
const app = express();
const port = 9090;
app.use(
cors({
origin: 'http://localhost:3000',
optionsSuccessStatus: 200,
credentials: true,
}),
);
app.use(express.json());
app.use(createMiddleware(...handlers));
app.listen(port, () => console.log(`Mock server is running on port: ${port}`));
// src/mocks/browser.ts
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';
const worker = setupWorker(...handlers);
export default worker;