본문 바로가기
챌린지/패스트캠퍼스 공부 루틴 챌린지

패스트캠퍼스 챌린지 12일차 (Mock Service Worker)

by 무벅 2022. 2. 4.
반응형

22.2.4 (금) +12days

Mock Service Worker

모킹(Mocking)이란?

Mock(모의 데이터)을 만들어서 활용하는 방식

통상적으로 data fetch를 해야하는 경우 통신을 통해 응답을 내려주는 서버가 있어야 함

 

서버가 없는 경우,

API 요청으로 내려올 데이터를 프론트에서 모킹하거나

서버의 역할을 해주는 무언가(데이터 fetch 해보기 강의에서는 github)가 필요

 

MSW

https://mswjs.io/

 

- 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

 

GitHub - mswjs/examples: Examples of Mock Service Worker usage with various frameworks and libraries.

Examples of Mock Service Worker usage with various frameworks and libraries. - GitHub - mswjs/examples: Examples of Mock Service Worker usage with various frameworks and libraries.

github.com

 

코드를 다운로드 받고 /exmplae/rest-react 에서 npm install 한다.

 

 

Username을 입력하고 Submit 하면 MSW로 정의한 데이터를 내리는 예제이다. handlers.jsreq.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

 

 

 

 

22.2.4 +12days

 

 

 

 

 

https://bit.ly/37BpXiC

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다

 

 

 

 

 

반응형

댓글