설명
MSW(Mock Service Worker) 는 API 요청을 가로채서 원하는 응답을 반환할 수 있도록 돕는 API Mocking 라이브러리로써 주로 테스트 환경이나 로컬 개발 환경에서 사용합니다.
장점
- 프론트엔드 중심 개발 : 백엔드가 준비되지 않은 상태에서도 프론트엔드 개발을 진행할 수 있습니다.
- 테스트 안정성 : 네트워크 상태나 외부 API의 영향을 받지 않고 테스트를 수행할 수 있습니다.
- 유연성 : 브라우저와 Node.js 환경 모두에서 동작합니다.
MSW 의 컨셉과 개념
API 요청과 응답의 흐름을 가상으로 재현하여, 실제 API가 없이 안정적이고 일관된 개발 및 테스트 환경을 제공하기 다음과 같은 방식과 개념을 사용하고 있습니다.
1. 요청 중심(Request-centric)
MSW는 클라이언트가 서버로 보내는 요청(Request)에 초점을 맞춥니다. 이를 통해 실제 API 요청과 유사한 흐름을 구현합니다.
- Request (요청) / Response (응답)
클라이언트(프론트엔드)와 서버에서 발생하는 HTTP 요청/응답입니다. MSW는 이 요청을 가로채고, 자유롭게 정의한 가짜 응답을 반환합니다.
2. 비침투적(Non-intrusive)
실제 작동 코드베이스를 수정하지 않고 MSW는 코드(ex: 실제 프론트 로직) 밖에서 작동하면서 네트워크 흐름 즉 요청을 가로채고 응답을 조작할 수 있습니다.
- Mock Definition (모킹 정의)
Mock Definition(모킹 정의) 이란 MSW 에서 제공하는 요청과 응답의 가짜 시나리오를 작성하는 과정으로 Handler(핸들러)를 통해 구현됩니다.
- Interception (가로채기) / Handler (핸들러)
MSW 는 요청 메서드와 URL을 기준으로 요청을 매칭하여 네트워크 요청을 가로채고, 응답을 정의하는 함수 Handler(핸들러)에 따라 응답(응답 데이터와 상태 코드 등등)을 반환합니다.
3. 환경 독립적(Environment-agnostic)
브라우저(Service Worker : 서비스 워커) 와 Node.js 환경에서 모두 사용할 수 있습니다.
- 브라우저 환경(Service Worker : 서비스 워커)
MSW는 브라우저 환경에서 서비스 워커를 등록하여 클라이언트와 네트워크 간의 요청 흐름을 제어합니다.
- Node.js 환경
Node.js 환경에서는 MSW가 setupServer를 사용하여 요청을 가로채는 HTTP 서버를 만듭니다. 주로 테스트 환경에서 주로 사용됩니다.
초기 세팅 및 사용 방법
1. 설치
pnpm add msw --save-dev
# msw init <PUBLIC_DIR>
# MSW 를 브라우저 환경에서 사용할 때 필요한 서비스 워커(Service Worker) 파일을 생성하고 설정하는 명령
pnpx msw init ./public
2. Handler(핸들러) 작성
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw'
export const handlers = [
// Intercept "GET https://example.com/user" requests...
http.get('https://example.com/user', () => {
// ...and respond to them using this JSON response.
return HttpResponse.json({
id: 'c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3d',
firstName: 'John',
lastName: 'Maverick',
})
}),
]
3. 개발 환경 실행
3.1 브라우저 환경(Service Worker : 서비스 워커)
애플리케이션의 진입점 파일에서 MSW를 실행합니다. 보통 src/main.tsx
또는 src/index.tsx
에 추가합니다.
// mocks/browser.ts
import { setupWorker } from 'msw';
import { handlers } from './handlers';
// 서비스 워커 초기화
export const worker = setupWorker(...handlers);
// main.tsx
if (process.env.NODE_ENV === 'development') {
const { worker } = await import('./mocks/browser');
worker.start();
}
3.2 Node.js 환경
Node.js 애플리케이션에서 서버를 import 하고 .listen() 메서드를 호출하여 활성화합니다.
// mocks/node.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
// index.ts
import { server } from './mocks/node'
server.listen()
// ...the rest of your Node.js application.
※ 테스트 환경에서 사용
Node.js 환경에서 주로 사용하는 방식이 Jest나 Vitest와 같은 테스트 러너를 사용
// vitest.setup.ts : Vitest 에서 MSW를 설정하는 예시
import { beforeAll, afterEach, afterAll } from 'vitest'
import { server } from './mocks/node'
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
실제 사용 코드
nextjs 의 특성상 client 와 server 에서 요청이 생성되는 등 여러 로직이 실행됨에 따라 MSW 설정과 초기화에 어려움이 있고 기타 여러 이유들로 어플리케이션 진입시점에 moking server 가 활성화 되는 MSW 기본 사용 구조를 사용하기가 쉽지 않아 다른 방법을 채택
※ express 로 별도의 서버를 통해 MSW 와 통합해 사용 하는 방식을 적용
참고 : https://velog.io/@wns450/msw-next-%EC%9D%B4%EC%8A%88#nextjs%EC%97%90%EC%84%9C-server%EC%99%80-worker-%EB%B6%84%EB%A6%AC-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0-
관련 내용이 상세히 있어 참고하시면 좋을듯 합니다.
Handler(핸들러)
// mocks/handlers/user.ts
import { http, HttpResponse } from "msw";
const API_URL = "api/users";
export const UserHandlers = [
// 로그인
http.get<any, any, LoginRes>(`${API_URL}/me`, () => {
return HttpResponse.json({
id: "user3356",
email: "yiccfee@naver.com",
});
}),
// 회원탈퇴
http.delete<any, any, any>(`${API_URL}/me`, () => {
return HttpResponse.text("ok");
}),
];
// mocks/handlers/index.ts
import { AuthHandlers } from "@/mocks/handlers/auth";
import { ScheduleHandlers } from "@/mocks/handlers/schedule";
import { UserHandlers } from "@/mocks/handlers/user";
const handlers = [...ScheduleHandlers, ...AuthHandlers, ...UserHandlers];
export default handlers;
브라우저 환경 세팅
// mocks/http.ts
import { createMiddleware } from "@mswjs/http-middleware";
import cors from "cors";
import express from "express";
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));
// eslint-disable-next-line no-console
app.listen(port, () => console.log(`Mock server is running on port: ${port}`));
서버 실행
// package.json 스크립트 코드
// nodemon, tsx 사용
script {
"mock": "nodemon --watch ./src/mocks/* --exec tsx watch ./src/mocks/http.ts",
}
참고
https://velog.io/@wns450/msw-next-%EC%9D%B4%EC%8A%88
https://velog.io/@ssoon-m/Next.js-app-directory%EC%9D%98-%EC%84%9C%EB%B2%84-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%97%90%EC%84%9C-msw-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
'nextjs' 카테고리의 다른 글
[Nextjs 15] Uncaught Error: Switched to client rendering because the server rendering errored 에러 (0) | 2025.02.07 |
---|---|
[Nextjs 15] Route handler cors 설정 (0) | 2025.02.07 |
nextjs middleware.js | ts (0) | 2024.11.26 |
[error] next/image Un-configured Host (0) | 2023.07.10 |
비동기 데이터로 jsx 구성 시 최적화 및 예외 처리 (0) | 2023.06.23 |