[FE] Mock Service Worker

seunghee.Rho·2025년 9월 19일

FE

목록 보기
25/26

1. MSW 설치

pnpm i msw -D
  • msw 라이브러리 프로젝트 설치
  • -D 옵션은 이 패키지가 개발 환경에서만 필요한 의존성임을 명시한다.
  • 실제 프로덕션 빌드에는 포함되지 않아 앱의 최종 번들 크기에 영향을 주지 않는다.

https://mswjs.io/docs/quick-start

2. 서비스 워커 스크립트 생성

npx msw init ./public --save
  • public 폴더 안에 mockServiceWorker.js라는 파일을 생성한다.
  • 브라우저는 mockServiceWorker.js를 통해 앱의 네트워크 요청을 감시하고 가로챌 수 있다.
  • 이 스크립트가 일종의 가상 프록시 서버 역할을 하며, 실제 서버로 요청이 나가기 전에 먼저 가로채게 된다.
  • ./public 폴더에 생성하는 이유는 대부분의 프레임워크에서 이 폴더를 정적 파일 루트로 사용하므로, 브라우저가 해당 주소로 쉽게 접근할 수 있기 때문이다.

3. 요청 핸들러(Request Handler) 정의

src/mocks/handler.ts

// success, loading, error 케이스 작성
import { delay, http, HttpResponse } from 'msw'
import mock from './mock.json'

// 성공 케이스: 요청 시 즉시 mock.json 데이터를 반환
export const success = http.get('https://pokeapi.co/api/v2/pokemon?limit=10&offset=0', () => {
    return HttpResponse.json(mock)
})

// 로딩 케이스: 요청 시 99999ms 동안 지연시킨 후 응답 (테스트용)
export const loading = http.get('https://pokeapi.co/api/v2/pokemon?limit=10&offset=0', async () => {
    await delay(99999)
})

// 실패 케이스: 요청 시 즉시 에러 상태를 반환
export const error = http.get('https://pokeapi.co/api/v2/pokemon?limit=10&offset=0', () => {
    return HttpResponse.error()
})

어떤 API 요청을 가로챘을 때, 어떤 가짜 응답을 돌려줄지 규칙을 정의한다.

만약 GET 요청이 이 주소(https://pokeapi.co/...)로 오면, 이렇게(HttpResponse.json(mock)) 응답해 라고 알려주는 시나리오 대본과 같다.


src/mocks/mock.json

{
    "count": 20000,
    "next": "https://pokeapi.co/api/v2/pokemon?offset=10&limit=10",
    "previous": null,
    "results": [
        {
            "name": "bulbasaur",
            "url": "https://pokeapi.co/api/v2/pokemon/1/"
        }
    ]
}

4. 워커 설정 및 실행 함수 생성

src/main.tsx

import { setupWorker } from "msw/browser";
import { success } from "./mocks/handler.ts";

const enableMSW = async (sign: "stop" | "start") => {
  const worker = setupWorker(success); // 3단계에서 만든 핸들러를 워커에 등록
  await worker[sign](); // 'start' 또는 'stop' 명령 실행
};

setupWorker 함수에 요청 핸들러들을 등록하여 워커 인스턴스를 생성하고, 이 워커를 시작(start)하거나 중지(stop)하는 enableMSW 함수를 만든다.

5. 애플리케이션 시작 전에 MSW 활성화

pnpm i @tanstack/react-query

API 요청 라이브러리인 @tanstack/react-query를 설치한다.


src/main.tsx

import { QueryClient, QueryClientContext } from "@tanstack/react-query";

enableMSW("start").then(() => {
  createRoot(document.getElementById("root")!).render(
    <StrictMode>
      <QueryClientContext value={new QueryClient()}>
        <App />
      </QueryClientContext>
    </StrictMode>
  );
});

enableMSW("start")를 호출하여 MSW를 활성화하고, 활성화가 완료된 후에 React 애플리케이션을 렌더링한다.

enableMSW("start")가 반환하는 Promise가 완료된 후에 앱을 렌더링하는 .then() 구조이다.

만약 MSW가 준비되기 전에 <App /> 컴포넌트가 렌더링되면, 컴포넌트 내부에서 발생하는 초기 API 요청을 MSW가 가로채지 못하고 실제 네트워크로 요청이 날아갈 수 있다.

.then()을 사용해 MSW가 요청을 가로챌 준비를 마치면, 그때 앱을 실행시킬 수 있도록 순서를 보장하는 것이다.

6. 컴포넌트에서 Mock API 호출 및 상태 변화 확인

<App /> 컴포넌트에서 @tanstack/react-query의 useQuery 훅을 사용해 API를 호출

// App.tsx
import "./App.css";
import { useQuery } from "@tanstack/react-query";

function App() {
  const { data, isLoading, isError } = useQuery({
    queryKey: ["pokeList"],
    queryFn: () =>
      // 이 fetch 요청이 바로 MSW의 가로채기 대상이 된다.
      fetch("https://pokeapi.co/api/v2/pokemon?limit=10&offset=0")
        .then((res) => res.json()),
  });

  // MSW의 'loading' 핸들러가 활성화되면 이 UI가 보인다.
  if (isLoading) {
    return <>로딩 상태</>;
  }

  // MSW의 'error' 핸들러가 활성화되면 이 UI가 보인다.
  if (isError) {
    return <>에러 상태</>;
  }
  
  // MSW의 'success' 핸들러가 활성화되면 가짜 데이터(mock.json)가 보인다.
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

export default App;

개발자 도구 네트워크 탭에 요청이 (from ServiceWorker) 라고 표시되는 것은 해당 네트워크 요청이 실제 서버로 전송된 것이 아니라, 브라우저에 설치된 서비스 워커(Service Worker)에 의해 가로채여 처리되었음을 의미한다.

MSW와 Service Worker의 관계

MSW(Mock Service Worker)가 바로 이 서비스 워커를 사용해 작동한다.

요청 가로채기(Intercept): App.tsx에서 fetch 함수를 호출하면, 이 요청은 실제 인터넷으로 나가기 전에 먼저 브라우저의 서비스 워커로 전달된다.

모의 응답(Mock Response): MSW가 설치한 서비스 워커는 들어온 요청의 URL을 확인하고, 미리 정의된 핸들러(예: success, error 핸들러)와 일치하는 것이 있는지 찾는다.

응답 반환: 일치하는 핸들러를 찾으면, 실제 네트워크 통신 없이 핸들러에 정의된 가짜 데이터(mock response)를 즉시 반환한다.

결론적으로, 개발자 도구의 (from ServiceWorker) 표시는 MSW가 성공적으로 활성화되어 API 요청을 가로채고 가짜 응답을 잘 내려주고 있다는 증거이다.

이를 통해 실제 백엔드 서버 없이도 프론트엔드 개발 및 테스트를 원활하게 진행할 수 있다.

profile
Web Developer

0개의 댓글