Next.js) msw로 백엔드 Mocking 해보기
msw는 Service Worker API를 사용해서 모든 요청을 가로채는 백엔드 API Mocking 라이브러리입니다.
REST API와 GraphQL 모두 지원하며 엔드포인트가 준비되지 않았을 때, 인터넷 연결이 느리거나 존재하지 않는 경우에 유용하게 쓰입니다.
Mocking은 진짜를 흉내낸다는 뜻을 가지고 있으며 Service Worker API는 PWA(프로그레시브 웹 앱)에도 유용하게 쓰이고 있습니다.
이번 글에서는 msw를 이용하여 get 요청과 getServerSideProps 코드를 작성해보겠습니다.
라이브러리 설치
yarn add -D msw
npx msw init public/
msw를 설치 후, 아래 명령어를 입력해주시면 자동으로 public 폴더에 mockServiceWorker.js 파일이 생성됩니다.
마지막으로 프로젝트 루트에 mocks라는 이름의 폴더를 생성해주세요. 오늘 테스트할 msw 코드들을 넣어둘 폴더입니다.
msw 환경 설정
// pages/_app.tsx
import { AppProps } from 'next/app'
if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') {
require('../mocks')
}
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
next.js에서 msw를 사용하려면 _app.tsx 파일이 필요합니다. NEXT_PUBLIC_API_MOCKING 환경 변수가 enabled가 되면 msw가 mock 작업을 수행한다는 뜻이며 disabled가 되면 mock 작업이 중단됩니다. 추가로 알아두실 점은 enabled 상태는 프로덕션과 개발 환경 모두 동일하게 mock 작업을 수행합니다.
때문에 .env 파일을 만들어주어야합니다.
// .env
NEXT_PUBLIC_API_MOCKING=enabled
Type.ts 작성
//mocks/type.ts
export interface Book {
title: string;
description: string;
}
export interface Review {
id: string;
author: string;
text: string;
}
예제에서 쓸 간단한 Type 파일을 작성하였습니다.
handlers.ts 작성
// mocks/handlers.ts
import { rest } from "msw";
import { Book, Review } from "./type";
export const handlers = [
rest.get("https://my.backend/book", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json<Book>({
title: "book 1",
description: "booooook",
})
);
}),
rest.get("/reviews", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json<Review[]>([
{
id: "1",
author: "marol",
text: "good vibes only",
},
])
);
}),
];
handlers.ts 파일에 저희가 테스트 하기 위한 백엔드 코드를 작성하겠습니다.
REST API를 사용하는 테스트용 백엔드 Mocking을 수행하며 책 정보와 리뷰를 전달해주는 코드입니다.
server.ts와 browser.ts 작성
이제 node.js 환경에서 작동하는 server.ts 파일과 브라우저 환경에서 작동하는 브라우저 환경에서 작동하는 browser.ts 파일을 작성하겠습니다. 이 파일들은 if else 문으로 환경에 맞게 실행할 예정입니다.
// mocks/server.ts
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
export const server = setupServer(...handlers);
// mocks/browser.ts
import { setupWorker } from "msw";
import { handlers } from "./handlers";
export const worker = setupWorker(...handlers);
async function initMocks() {
if (typeof window === "undefined") {
const { server } = await import("./server");
server.listen();
} else {
const { worker } = await import("./browser");
worker.start();
}
}
initMocks();
export {};
이제 개발 서버를 구동하고 localhost:3000에 접속해보겠습니다.
[MSW] Mocking enabled.
브라우저 콘솔에 위와 같은 텍스트가 출력되면 msw가 제대로 구동 된 것입니다!
msw 코드 확인을 위한 컴포넌트 작성
// pages/index.tsx
import type { NextPage } from "next";
import { useState } from "react";
import { Book, Review } from "../../mocks/type";
interface Props {
book: Book;
}
const Test: NextPage<Props> = ({ book }: Props) => {
const [reviews, setReviews] = useState<Review[] | null>(null);
const handleGetReviews = () => {
fetch("/reviews")
.then((res) => res.json())
.then(setReviews);
};
return (
<>
<div>
<h1>{book.title}</h1>
<p>{book.description}</p>
<button onClick={handleGetReviews}>Load reviews</button>
{reviews && (
<ul>
{reviews.map((review) => (
<li key={review.id}>
<p>{review.text}</p>
<p>{review.author}</p>
</li>
))}
</ul>
)}
</div>
</>
);
};
export default Test;
export async function getServerSideProps() {
const res = await fetch("https://my.backend/book");
const book = await res.json();
return {
props: {
book,
},
};
}
버튼 클릭 시 get 요청으로 책 리뷰를 가져오며 책 목록을 getServerSideProps로 미리 렌더링하는 코드입니다.
브라우저 콘솔에도 정상적으로 저희가 요청했던 mock 백엔드 코드가 실행된 것을 확인 할 수 있습니다!
Reference
https://github.com/vercel/next.js/tree/canary/examples/with-msw
GitHub - vercel/next.js: The React Framework
The React Framework. Contribute to vercel/next.js development by creating an account on GitHub.
github.com