본문 바로가기
nextjs

Next.js 환경에서 express, MSW 를 활용한 mock 서버

by spare8433 2025. 1. 5.

설명

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