Next.js에서 MSW로 API 없이 프론트 개발하기

김하은·5일 전
0

Next.js

목록 보기
2/2

사용 계기

로잇 프로젝트를 개발하면서 원래는 API 개발이 늦어져도 UI만 먼저 간단히 작업하면 된다고 생각했지만, 회원가입 페이지가 3단계로 나뉘면서 상태 관리해야 할 요소가 많아져 코드 작성에 시간이 걸릴 것으로 예상됐습니다.

API가 완성될 때까지 기다리면, 프로젝트 막바지에 급하게 코드를 작성하는 일이 발생할 가능성이 높아 보였고, 이를 방지하기 위해 백엔드를 흉내내 Mocking API를 요청을 하는 방식으로 개발을 진행하기로 했습니다.

MSW(Mock Service Worker)를 선택한 이유

처음에는 JSON Server를 사용해 간단한 API 응답을 만들려고 했지만, 실제 서비스처럼 에러 처리(예: 모달 표시, 에러 메시지 출력)까지 구현 하기에는 한계가 있었습니다.

그래서 해결책을 찾던 중, Nock과 MSW(Mock Service Worker)를 발견했습니다.

결과적으로 향후 개발할 WebSocket API 기능까지 지원하고, 브라우저 환경에서도 API 요청을 처리할 수 있는 MSW를 선택했습니다.

MSW의 작동 원리

출처: https://velog.io/@khy226/msw로-모의-서버-만들기

MSW는 API 요청을 가로채서 미리 정의된 응답을 반환하는 도구입니다.

브라우저 환경에서는 Service Worker(SW)를 이용해 네트워크 요청을 중간에서 가로채고, Node.js 환경에서는 Request Interceptor를 활용하여 요청을 처리합니다.

위 사진을 통해 설명하면

  1. (요청 발생)
  • 사용자가 fetch 또는 axios 같은 HTTP 요청을 보냄
  • 원래는 이 요청이 실제 백엔드 서버로 가야 함
  1. (MSW의 서비스 워커가 요청을 가로챔)
    • 브라우저에서 Service Worker로 동작
    • 프론트엔드에서 보내는 API 요청을 네트워크 단계에서 가로채서 Mock 응답을 반환함
    • 실제 서버와 통신하지 않고, 미리 정의된 핸들러를 기반으로 응답을 제공
  2. (요청 핸들러에서 요청을 확인)
    • http.get(), http.post() 등의 핸들러를 설정하여 요청 URL과 메서드에 따라 특정 응답을 반환
    • 예를 들어, /api/user에 대한 GET 요청이 오면 { name: "Haeun Kim" } 같은 응답을 줄 수 있음
  3. (요청에 맞는 응답을 반환)
    • 요청이 핸들러 목록과 매칭되면, 사전에 정의된 응답을 찾음
    • 브라우저는 실제 서버에서 응답을 받은 것처럼 처리함
  4. (클라이언트가 응답을 받음)
    • 최종적으로 브라우저는 MSW가 반환한 Mock 응답을 실제 서버 응답처럼 받게 됨
    • 이 과정에서 HTTP 상태 코드(200, 400, 500 등)와 JSON 데이터를 반환할 수 있음
    • 예를 들어, HttpResponse.json({ userId: 1, name: "Haeun Kim" }, { status: 200 }) 같은 응답이 반환됨
    • 따라서 백엔드 개발 없이도 프론트엔드 개발과 테스트가 가능해짐

MSW 사용 방법

공식 문서를 참고해서 Next.js 프로젝트에서 MSW를 설정하고 사용하는 방법을 정리했습니다.

단계브라우저 환경Node.js 환경 (SSR, Jest)
1. 초기화setupWorker().start()로 서비스 워커 등록setupServer().listen()으로 요청 인터셉트
2. 요청 발생브라우저에서 API 요청 (fetch, axios)서버 코드에서 API 요청 (getServerSideProps, test 등)
3. 요청 가로채기서비스 워커가 요청을 가로채고 핸들러를 확인HTTP 인터셉터가 요청을 가로채고 핸들러를 확인
4. Mock 응답 반환미리 정의된 응답을 반환테스트 코드에서 미리 정의된 응답을 반환

1. MSW 라이브러리 설치

npm install msw --save-dev

2.  서비스 워커 파일 생성 (mockServiceWorker.js)

Next.js에서는 public 폴더 내 정적 파일을 브라우저에서 직접 접근할 수 있기 때문에, MSW의 서비스 워커 파일을 public 폴더에 생성해야 합니다.

npx msw init public --save
  • 생성된 파일

    📂 public
    ┗ 📜 mockServiceWorker.js ✅ (MSW 서비스 워커 파일)

  • 서비스 워커 등록 과정

    1. 브라우저가 mockServiceWorker.js를 public 폴더에서 가져옴
    2. setupWorker().start() 실행 시 브라우저가 서비스 워커를 등록
    3. 이후 브라우저의 모든 네트워크 요청이 서비스 워커를 거치게 됨
    4. MSW가 요청을 가로채고, 미리 정의된 Mock 응답을 반환

3. API 핸들러 작성

API 요청을 가로채고 응답을 반환하는 핸들러를 작성합니다. 이 단계는 일단 틀만 만들어놓고 세부 내용은 가장 나중에 작성했습니다.

// mocks/handlers.js

import { http, HttpResponse } from "msw";

async function checkUserExists(email) {
  const dummyUserDatabase = ["test@example.com", "user@domain.com"];
  return dummyUserDatabase.includes(email);
}

export const handlers = [
  http.post("/api/send-email-code", async ({ request }) => {
    const { email } = await request.json();

    if (!email) {
      return HttpResponse.json(
        { error: "이메일이 누락되었습니다." },
        { status: 400 },
      );
    }

    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
      return HttpResponse.json(
        { error: "잘못된 이메일 형식입니다." },
        { status: 400 },
      );
    }

    const existingUser = await checkUserExists(email);
    if (existingUser) {
      return HttpResponse.json(
        { error: "이미 가입된 이메일입니다." },
        { status: 409 },
      );
    }

    return HttpResponse.json(
      { message: "인증 코드가 전송되었습니다." },
      { status: 200 },
    );
  }),

 // 중략
];

4. MSW 실행 설정

Next.js에서는 브라우저에서 worker를 실행하고, 서버에서 server를 실행해야 합니다.

  • 브라우저 실행 (CSR)
    // mocks/browser.ts
    
    import { setupWorker } from 'msw/browser'
    import { handlers } from './handlers'
     
    export const worker = setupWorker(...handlers)
  • 서버 실행(SSR)
    // mocks/server.ts
    
    import { setupServer } from "msw/node";
    import { handlers } from "./handlers";
    
    export const server = setupServer(...handlers);

5. MSW 실행을 위한 설정 함수 추가

Next.js에서 MSW를 자동으로 실행하기 위한 파일을 생성합니다.

// mocks/index.ts

export async function initMsw() {
  if (typeof window === "undefined") {
    // 서버에서 실행
    const { server } = await import("./server");
    server.listen();
  } else {
    // 클라이언트에서 실행
    const { worker } = await import("./browser");
    await worker.start();
  }
}

6. Next.js에서 MSW 활성화

MSW를 Next.js에서 사용하려면 app.tsx 또는 providers.tsx에서 실행해야 합니다.

if (process.env.NODE_ENV === "development") {
  import("../mocks").then(({ initMsw }) => initMsw());
}

결과

브라우저에서 API 요청 테스트

정상 응답

이미 가입된 이메일 요청인 경우 에러 반환

회고

  • API가 준비될 때까지 기다리는 것보다 MSW를 활용하는 것이 훨씬 효율적이었음
  • 특히, 3단계 회원가입 페이지처럼 상태 관리가 중요한 경우 API가 없어도 미리 개발하고 테스트할 수 있어서 유용했음
  • 현재는 SSR을 활용한 페이지가 없지만, 향후 최적화 과정에서 SSR을 적용할 계획이므로, Node.js 환경에서의 MSW 설정도 유용하게 활용될 것으로 예상됨
  • 결론적으로, MSW는 개발 생산성을 높이고, 프론트엔드와 백엔드의 의존성을 줄여줘서 사용할 만한 가치가 있었음

참고 자료

profile
아이디어와 구현을 좋아합니다!

0개의 댓글

관련 채용 정보