22.2.4 (금) +12days
Mock Service Worker
모킹(Mocking)이란?
Mock(모의 데이터)을 만들어서 활용하는 방식
통상적으로 data fetch를 해야하는 경우 통신을 통해 응답을 내려주는 서버가 있어야 함
서버가 없는 경우,
API 요청으로 내려올 데이터를 프론트에서 모킹하거나
서버의 역할을 해주는 무언가(데이터 fetch 해보기 강의에서는 github)가 필요
MSW
- Interception on the network level
- Service Worker API
- REST API & GraphQL support
Examples
Learn by inspecting how Mock Service Worker integrates with your favorite tools.
API types
Each example in this section contains a complete showcase of Mock Service Worker usage in development, unit, and E2E tests. A great place to start with API mocking when all you know is the API type your application uses.
React
먼저 REST API의 예제를 살펴본다.
https://github.com/mswjs/examples
코드를 다운로드 받고 /exmplae/rest-react 에서 npm install 한다.
Username을 입력하고 Submit 하면 MSW로 정의한 데이터를 내리는 예제이다. handlers.js에 req.body 부분을 JSON.parse(req.body); 로 감싸서 response 파라미터로 보낸 데이터가 제대로 내려오게 수정한다.
import { rest } from 'msw'
export const handlers = [
rest.post('/login', (req, res, ctx) => {
const { username } = JSON.parse(req.body)
return res(
ctx.json({
id: 'f79e82e8-c34a-4dc7-a49e-9fadc0979fda',
username,
firstName: 'drawyourmind',
lastName: 'Maverick',
}),
)
}),
]
GraphQL 예제도 위와 같은 방식으로 실행하여 확인할 수 있다.
Request flow diagram
Browser
This library registers a Service Worker that listens to the application's outgoing requests via the fetch event, directs those requests to the client-side library, and sends a mocked response, if any, to the worker to respond with.
Here's a high-level overview of the Mock Service Worker request flow:
Mocking REST API
Install
$ npm install msw --save-dev
# or
$ yarn add msw --dev
Imports
// src/mocks/handlers.js
import { rest } from 'msw'
Request handler
// src/mocks/handlers.js
import { rest } from 'msw'
export const handlers = [
// Handles a POST /login request
rest.post('/login', null),
// Handles a GET /user request
rest.get('/user', null),
]
Response resolver
// src/mocks/handlers.js
import { rest } from 'msw'
export const handlers = [
rest.post('/login', (req, res, ctx) => {
// Persist user's authentication in the session
sessionStorage.setItem('is-authenticated', 'true')
return res(
// Respond with a 200 status code
ctx.status(200),
)
}),
rest.get('/user', (req, res, ctx) => {
// Check if the user is authenticated in this session
const isAuthenticated = sessionStorage.getItem('is-authenticated')
if (!isAuthenticated) {
// If not authenticated, respond with a 403 error
return res(
ctx.status(403),
ctx.json({
errorMessage: 'Not authorized',
}),
)
}
// If authenticated, return a mocked user details
return res(
ctx.status(200),
ctx.json({
username: 'admin',
}),
)
}
Intergrate > Browser
Setup
Mock Service Worker operates client-side by registering a Service Worker responsible for requests interception. However, we don't have to write any of the worker's code by ourselves, but rather copy the worker file distributed by the library. Mock Service Worker provides a dedicated CLI to help us do that.
## $ npx msw init <PUBLIC_DIR> --save
$ npx msw init public/ --save
프로젝트 실습
fetch-msw/src/index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
// Start the mocking conditionally.
if (process.env.NODE_ENV === "development") {
const { worker } = require("./mocks/browser");
worker.start();
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
fetch-msw/src/mocks/browser.js
import { setupWorker } from "msw";
import { handlers } from "./handler";
export const worker = setupWorker(...handlers);
fetch-msw/src/mocks/handler.js
import { rest } from "msw";
export const handlers = [
rest.get("/login", async (req, res, ctx) => {
// const { username } = req.body;
return res(ctx.json({ id: "213", firstName: "jeongmu", lastName: "moo" }));
}),
rest.get(
"https://raw.githubusercontent.com/techoi/raw-data-api/main/simple-api.json",
async (req, res, ctx) => {
return res(
ctx.json({
data: {
people: [
{
name: "jeongmu",
age: 135,
},
{
name: "timmy",
age: 13,
},
{
name: "cindy",
age: 15,
},
{
name: "judy",
age: 25,
},
{
name: "marry",
age: 64,
},
{
name: "tommy",
age: 109,
},
],
},
})
);
}
),
];
fetch-msw/src/components/TestMocking.jsx
import React, { useState } from "react";
const Item = ({ name, age }) => {
return (
<li>
name: {name} / age: {age}
</li>
);
};
const url =
"https://raw.githubusercontent.com/techoi/raw-data-api/main/simple-api.json";
export default function TestMocking() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const handleClick = () => {
fetch(url)
.then((response) => {
return response.json();
})
.then((json) => {
setData(json.data);
})
.catch((error) => {
setError(`Something Wrong: ${error}`);
});
};
const handleClick2 = () => {
fetch("/login")
.then((response) => {
return response.json();
})
.then((json) => {
console.log(JSON.stringify(json));
});
};
if (error) {
return <p>{error}</p>;
}
return (
<div>
<button onClick={handleClick}>데이터 가져오기</button>
<button onClick={handleClick2}>데이터 가져오기2</button>
{data && (
<ul>
{data.people.map((person) => (
<Item
key={`${person.name}-${person.age}`}
name={person.name}
age={person.age}
/>
))}
</ul>
)}
</div>
);
}
정리
Mocking ⇒ 모의 데이터 활용
Browser ⇒ Service worker 활용
REST API / GraphQL ⇒ 모두 모킹이 가능
mock ⇒ handler / browser만 있어도 동작
public ⇒ npx msw init <PUBLIC_PATH>
기타 커스텀 ⇒ query / patching / error
본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다
댓글