My Boundary As Much As I Experienced

내가 MSW를 구현한 방법 (HTTP, HttpResponse) 본문

FrontEnd/React

내가 MSW를 구현한 방법 (HTTP, HttpResponse)

Bumang 2024. 3. 21. 03:10

MSW란?

Mock Service Worker의 준말이다.
이때 Service Worker는 앱의 백그라운드에서 실행되는 브라우저가 제공하는 기능이다.

브라우저와 앱의 중간에서 이벤트를 listening하고 있는 존재라고 보면 된다.

(PWA나 Firebase Cloud Message같은 기능들을 구현해보려고 했던 개발자들은 사용해본 경험이 있을 것이다.)

 

Mock이란 단어에서 알 수 있듯이, MSW는 브라우저의 백그라운드에서

비동기 api통신 호출을 가로채서 가짜 응답을 해주는 Proxy의 역할을 한다.

 

왜 필요한가?

 

백엔드에서 API를 아직 주지 않았을 때, api 명세서대로 객체를 생성하여

일단 호출 받았다 치고 화면 구현해본 경험이 다들 있을 것이다.

그러나 이런 방식으로 모사하는건 마크업을 확인하는 용도로만 쓰지,

실제 api호출 함수를 만들어서 이를 비즈니스 로직대로

커스텀 훅으로 모듈화해보는 것까지 해보기는 어렵다.

 

그러나 MSW를 사용하면 실제 api를 찔러보고

그 결과값을 반환해보는 과정 그대로를 모사할 수 있기 때문에,
한 번 환경을 세팅해놓으면 api가 나오기 전부터 api호출을 거의 그대로 구현할 수 있다.

이를 통해 테스트 환경을 구축해놓으면 api가 나오기 전부터 api호출을 테스트해볼 수 있다.

이렇듯 제대로 된 프론트엔드 테스트 환경을 효과적으로 구축할 수 있다는 장점도 있다.

 

나도 저번 부트캠프 때 백엔드 개발자들이 api를 내주기 전에 서버 호출을 모사해보려고 사용해봤다.

 

그런데 이번에 지원한 회사 중 하나가 동작하지 않는 api 엔드포인트와 응답값을 주면서

호출 성공 됐다고 치고 구현해보라는 과제를 줘서, 아, 그렇다면 MSW를 활용해서

'내가 실제로 react-query hook만드는 방식을 재현해서 보여주자'라는 의도로 기억을 되살려서 다시 세팅해보기로 했다.

 

 

그러나 생각 이상으로 변덕스럽게 바뀌는 문법...

현재 MSW 공식 문서로는 파일을 어떻게 나누는지,

폴더 구조를 어떻게 하는지 등의 컨벤션을 파악하기 힘들었다.

그래서 MSW를 연동해본 다른 블로그들을 참고해서 써보려고 했으나...

모든 글들이 다 rest하는 메소드를 이용해서 구현하고 있었다.

 

그러나 실제 msw로 rest 메소드를 import해보면 현재 rest문법은 msw에 존재하지 않는다는 얘기가 나온다.

공식 문서 상에서도 rest문법을 쓰지 않고 http, HttpResopnsee 등의 메소드들을 사용하고 있다.

 

처음엔 @types를 안 깔아서 TS가 내는 에러인가 의심도 했었는데, 역시나 문법이 어느 순간 바뀐게 맞았다.

보통 이렇게 문법이 바뀌면 이전 버전의 문서는 공식사이트 어딘가에 남겨주는걸로 알고 있는데,

어떠한 예고도 보존해놓은 흔적도 보이지 않는다🫥 너무하다.

 

http, HttpResponse를 이용한 구현

하여튼 신 문법 http라는 메소드를 사용해서 구현하면 되는거 같다.

그런데 이때 제로초 node.js수업을 약간씩 들었던게 조금은 도움이 됐던거 같다.

http 핸들러를 구성하는 방식이 express 핸들러를 구성하는 방식과 유사해서 개념 자체는 어렵지 않았다.

 

지금부터 http, HttpResponse 메소드의 사용방법을 적어보겠다.

일단 `npm i msw`를 해서 msw를 깔면 아래처럼 npx init을 하라고 한다.

 npx msw init public/ --save

 

이걸 다 하면 public폴더에 mock service worker가 세팅된다.

그 이후엔 src파일에 broswer, handlers, server파일을 각각 만드는데, 내용은 아래와 같다.

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

import { handlers } from "./handlers";

// 브라우저의 service worker에 handler를 제공하여 등록한다.
export const worker = setupWorker(...handlers);
// handlers.ts
import { http, HttpResponse } from "msw";
import { END_POINTS } from "@/constants/api";

import library from "./data/library.json";
import login from "./data/login.json";

export const handlers = [
  http.post(END_POINTS.LOGIN, () => { // http로 post요청을 받았을 시를 포착
    return HttpResponse.json(login); // HttpResponse훅으로 login.json 파일로 응답해준다. (return을 같이 써주는게 중요하다.)
  }),

  http.get(END_POINTS.LIBRARY, (res) => { // get요청을 받았을 시
  	// 단순 응답이 아니라면 아래처럼 내용을 편집해서 따로 응답할 수 있다.
    const id = res.request.url.split("=")[1];

    if (id === "wellness") {
      return HttpResponse.json(library.slice(5, 20));
    } else if (id === "medical") {
      return HttpResponse.json(library.slice(10, 30));
    } else if (id === "crime") {
      return HttpResponse.json(library.slice(16, 24));
    } else {
      return HttpResponse.json(library);
    }
  }),
  
  ...

  http.get("*", () => { // 이 외의 요청은 그냥 반환한다. 이 부분을 안 쓰고 위에 있는 핸들러에도 안 걸리는 요청이 있을 시 msw가 시끄럽게 콘솔 창에서 경고해대기 때문에 적어주는게 좋다.
    return;
  }),
];
// server.ts
import { setupServer } from "msw/node";

import { handlers } from "./handlers";

// server에다 handlers를 공급한다.
export const server = setupServer(...handlers);

 

src/mocks에 browser, handler, server ts파일을 생성했고, JSON 데이터가 있는 data파일을 만들었다.

 

 

 

앞으로 이 기술을 사용하는 것이 좋을까?

앞으로 프론트 테스트 환경을 구축하는 회사가 많아지면서

MSW의 인기가 계속 높아질거 같아 공부해둘 가치는 있는거 같다.

좋은 기술스택으로 활용될 수 있겠지만, 문서 경험이 좋지 않고,

뜬금없는 문법 변화가 있다는걸 제대로 알려주지 않는 점은 매우 아쉽다.

1년 밖에 안 된 사용 방식이 벌써 deprecated되거나 하는 등

msw의 문법 변화 텀은 너무 빠른거 같다. 아직 안정화되지 않은 느낌이다.

(환경 세팅하면서 시행착오가 너무 많아서.. 3시간 이상을 소요할지 예상하지 못했다.)

 

과제 시간 상 거의 get요청 모사밖에 높이진 못했는데,

동적 패러미터를 탐지해서 다른 응답을 내주는 방법들이나, 400에러 500에러 내주는 부분까지 배워서

미리 보일러템플릿을 구축해놔야겠다는 생각을 하게 되었다.