[MSW] MSW(2.0)를 이용한 모킹 API 구축하기

Bomin·2024년 1월 28일
2

[TIL]

목록 보기
2/4
post-thumbnail

2023.10.23 MSW 2.0 버전이 릴리즈되었다. 이 글은 2.0을 기반으로 쓰여졌으며,
Vite,React,TypeScript,tailwindcss 를 사용하였다.

개요

프론트엔드 개발자라면 한번 쯤은 API가 아직 안나와서 개발 진행이 더뎌지거나 멈췄던 경험이 있을 것이다.

그럴 때 백엔드 API가 나오기 전 Mocking을 통해 사전 개발을 진행 할 수 있는데, 간단하게는 json 파일에 임시 데이터를 사용하거나 json-server, mock-server 등을 통해 진행할 수 있다.

하지만 실제 API가 아니기에 실제 화면을 구성하고자하는 구현 단계에는 케이스별로 임의의 상태를 만들어 보면서 개발하거나 그 자체를 디버깅하기에 어려움이 있을 수 있다.

그렇다면 실제 API를 사용하는 것처럼 네트워크 수준에서 Mocking할 수는 없을까?

😎 바로 MSW를 통해 이를 해결할 수 있다.

MSW 란?

Mock Service Worker는 서비스 워커를 이용하여 API를 모킹하는 라이브러리로, 사용법이 간단하고 모킹 서버를 따로 띄울 필요가 없다는 장점을 가지고 있다.

MSW는 서비스 워커를 사용하여 네트워크 호출을 가로챈다. API 요청을 가로채서 사전에 설정해둔 목업 데이터를 넘겨주도록 설정해 주는 도구라고 생각하면 된다. 주로 아래에 경우 사용된다.

  • 백엔드 API 개발과 프론트엔드 UI 개발이 동시에 진행되야하는 경우, 백엔드 API 구현이 완료될 때까지 프론트엔드 팀에서 임시로 사용하기 위한 가짜(mock) API 구현
  • TDD 시 실제 백엔드 API에 네트워크 호출을 하는 대신에 훨씬 빠르고 안정적인 가짜 API 서버를 구축

MSW의 특징

  • 모킹이 네트워크 단에서 일어나므로 프론트엔드 코드를 실제 백엔드 API와 통신하는 것처럼 작성할 수 있다. -> 대체가 쉬워 개발 생산성 증가!

  • 동일한 요청 핸들러(handler) 코드를 여러 환경(브라우저 환경, Node.js 환경,Jest나 Cypress)에서 공유해서 사용가능하다. -> 코드 최소화, 유지 보수성

  • REST API, GraphQL API 둘 다 지원한다.

MSW 시작하기

설치하기

npm install msw --save-dev
#or
yarn add msw --dev
  • 개발 환경에서만 사용하기 때문에 꼭 devDependencies로 설치하기는 필수!

기반 코드 자동 생성

npx msw init public/ 
  • public/ : 프로젝트에서 정적 리소스를 두는 폴더로 지정해준다.

요청 핸들러 작성

요청이 들어왔을 때 임의의 응답을 해주는 핸들러(handler)를 먼저 만들어보자.
간단한 투두리스트로 예제를 구현해보았다.

// src/mocks/handlers.ts 
import { http, HttpResponse } from 'msw';

export type Todo = {
	id: number;
	name?: string;
};

const todos: Todo[] = [
	{ id: 1, name: '할일1' },
	{ id: 2, name: '할일2' },
	{ id: 3, name: '할일2' },
];

export const handlers = [
	// TODOLIST - GET
	http.get('/todos', () => {
		return HttpResponse.json(todos, {
			status: 201,
			headers: {
				'Content-Type': 'application/json',
			},
		});
	}),
	// TODOLIST ADD - POST
	http.post('/todos', async ({ request }) => {
		const requestData = await request.json();
		const name = requestData?.toString();
		
		const newTodo = { id: todos.length + 1, name };
		todos.push(newTodo);
		
		return HttpResponse.json(todos, { status: 201 });

	}),
];
  • 더 다양한 HttpResponse 사용 방법을 보려면 공식문서를 참고하자.

서비스 워커 생성

// src/mocks/browser.ts
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers' 

export const worker = setupWorker(...handlers)
  • msw/browser 모듈에서 제공하는 setupWorker() 함수를 사용해서 서비스 워커를 생성한다.

모킹 활성화

  • 이제 애플리케이션에 서비스 워커를 삽입하여 모킹 API를 활성화 해주자.
  • 개발 환경인지 분기를 주어서 모킹을 활성화 해준다.
// /src/index.tsx or main.tsx(vite)
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';

async function enableMocking() {

// 일반적인 경우
// if (process.env.NODE_ENV !== 'development') { 

// vite의 경우
	if (!import.meta.env.DEV) {
		return;
	}

	const { worker } = await import('./mocks/browser.ts');

// 서비스 워커 시작
	return worker.start();
}

enableMocking().then(() => {
	ReactDOM.createRoot(document.getElementById('root')!).render(
		<React.StrictMode>
			<App />
		</React.StrictMode>
);
});

테스트

[MSW] Mocking enabled.
  • 개발자 도구 콘솔에 이렇게 뜨면 성공이다!

리액트 UI

  • 최초 랜더링 시에 GET /todos를 호출 TODOLIST 가져와서 화면에 그려준다.
  • 에 새로운 할 일을 넣고 버튼을 누르면 POST /todos를 호출한다.
import { useEffect, useState } from 'react';
import { Todo } from '../mocks/handlers';

export default function App() {
	const [todos, setTodos] = useState<Todo[]>([]);
	const [todo, setTodo] = useState('');
	const [loading, setLoading] = useState(false);

	useEffect(() => {
		setLoading(true);
		fetch('/todos')
			.then((res) => res.json())
			.then((data) => {
				setTodos(data);
				setLoading(false);
			});
	}, []);

  const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
	event.preventDefault();
	setLoading(true);
	fetch('todos', {
		method: 'POST',
		headers: {
		'Content-Type': 'application/json',
		},
		body: JSON.stringify(todo),
	}).then((res) => {
		// todo 추가 후 바로 새리스트 불러오기
		fetch('/todos')
			.then((res) => res.json())
			.then((data) => {
				setTodo('');
				setTodos(data);
				setLoading(false);
			});
		});
	};

  return (
	<div>
		<h2 className='text-xl'>TODOLIST</h2>
		<ul>
		{todos.map((todo) => (
			<li key={todo.id}>{todo.name}</li>
		))}
		</ul>

		<form onSubmit={handleSubmit}>
			<input
				type='text'
				name='todo'
				placeholder='새로운 할일'
				disabled={loading}
				value={todo}
				onChange={({ target: { value } }) => setTodo(value)}
			/>
			<button disabled={!todo}>추가</button>
		</form>
	</div>
	);
}

구현 화면

  • 간단한 투두리스트가 모킹 API를 통해 잘 구현된 것을 확인할 수 있다.

마무리

MSW로 무한 스크롤 연습하려고 만들다가 MSW에 대한 포스팅까지 하게되었다. 평소 json파일로 간단한 모킹 데이터로만 사용하고 있었는데 앞으로 MSW를 자주 사용하게 될 것같다.

무엇보다 백엔드에 의존하지 않고 프론트엔드 개발을 할 수 있고, 진짜 API로 바꿀 때 코드 수정이 거의 없어서 확실히 생산성이 좋은 것 같다.

또한 추후에 테스트 코드 작성 시에도 활용해보고 블로그에 정리해볼 예정이다.

참고자료
카카오 기술블로그
블로그
공식문서

profile
Frontend-developer

0개의 댓글