MSW (Mocking Service Worker) ?

ChangHyeon Bae·2023년 2월 14일
0

개발 지식

목록 보기
1/1
post-thumbnail

🤔 MSW 란?

⭐️ 저희가 백엔드와 협업을 하면서 개발을 진행할 때 항상 마주하는 문제가 있습니다.

기획 : XX 작업은 진행 중인가요?
나 : 네? 그게... 아직 API 부분이 준비되지 않아서 보류 중이라 아마 빠르면 다음주부터 시작해서
조금 기다리셔야 될거 같습니다 ㅠㅠ

아마 위와 같은 상황은 프론트엔드 개발자가 프로젝트를 진행하면서 마주하는 심심치 않은 상황입니다.
그러면 API 구현이 되어있지 않았지만, 그 부분에 대해 개발을 들어가야 하는 경우 저희는 어떤 방법을 써왔을까요? ( 백엔드 개발과 관련해 다소 종속적인 모습을 보입니다. )

그래서 프론트 개발을 진행하면서,
" API가 개발되기 전에 프론트엔드 개발을 마치자 " => Mocking 을 활용해보자 !
라는 결론을 가지게 되었습니다.

⭐️ 그럼 Mocking이란 무엇일까요 ?

먼저, 기획자가 요구사항을 개발자에게 전달 합니다. 그리고 백엔드와 종속적인 개발 영역인 경우에는, 프론트엔드 개발자는 필요한 API의 스펙을 사전 협의하여 백엔드 개발자와 상의 합니다.

API 문서를 사전에 제공받은 경우, 사전 개발을 진행하게 되고 API를 통해 실제로 연동할 때까지 큰 변화 없이 개발을 진행 할 수 있습니다.

하지만, API 자체에 대한 의존성을 일단 가져가지 않고, Mocking 을 통해 개발을 진행한 다음에 실제 백엔드에서 API에 대한 구현을 마친 후 API의 실제 인터페이스에 맞게 변환하는 과정을 따로 가지는 개발 방법으로 진행하기도 합니다. ( 다소 비효율적인 모습, 개발 기간이 늘어날 수도 있는 단점을 가지고 있습니다. )

이전에 저희가 사용했던 Mocking 방법에는 대표적으로 2가지의 방식을 가지고 사용했습니다.

  1. 화면에 필요한 데이터의 상태를 애플리케이션의 내부 로직에 직접 Mocking 해서 필요한 화면에 붙이는 방식
  2. Mock 서버를 별도로 만드는 방식

대표적으로 Mocking 을 활용하여 개발을 진행할 때 위와 같은 2가지 방식으로 이루어져왔지만 2가지 방식은 앞서 말씀드린 비효율적인 개발 방법, 그리고 개발 기간이 늘어남과 개발 공수의 증가와 같은 단점을 가지고 있습니다.

이외에도, 각 화면에 대한 테스팅 및 디버깅 시에 어려움이 발생합니다.
결과물을 확인하고자 하는 인원이 담당 프론트엔드 개발자가 아니라면, 예를 들어 에러 화면을 보려고 해도 크롬 개발자 도구가 요청을 블록 처리할 가능성이 높아 특정 상태의 화면을 다른 사람들에게 공유하기가 어렵고, API 스펙 처럼 실제 방생하는 상황을 모의하기가 상당히 어렵습니다.

또한, 대기, 로딩, 에러등의 API의 실제 응답 상태에 따른 다양한 구현을 가지고 있을 경우도 있습니다. 이경우에는 각 단위 개발은 어떻게 진행한다고 하더라도 실제 화면을 구성하기 위한 구현 단계에서는 각 케이스 별로 임의의 상태를 만들어 보면서 개발하거나 그 자체를 디버깅(모든 소프트웨어에서 소스 코드의 오류 또는 버그를 찾아서 수정하는 과정)하기에 어려움이 있습니다.

위와 같이 Mocking 활용하는 수준에서는 다양한 단점과 새로운 문제점이 발생할 수 있습니다. 그러면 저희가 개발을 진행하는데에 있어 어느정도 수준의 Mocking 방법이 필요한걸까요?

⭐️ 실제 API를 사용하는 것처럼 네트워크 수준의 Mocking

결국 백엔드의 종속적이지 않은 개발을 진행하기 위해서는 실제 API를 사용하는 것처럼 네트워크 수준에서 Mocking을 구성하여 개발을 진행하는 방법입니다.

그중에서도 네트워크 수준의 Mocking을 제공하고, 공식문서가 잘되어있고, 사용방법이 편리한 MSW (Mocking Service Worker) 를 소개와 동시에 활용 방법을 소개 드리겠습니다.

⭐️ MSW 소개 해보기

먼저 MSW 의 공식 홈페이지를 한번 살펴보겠습니다.

들어가자마자 보이는 문구들과 사용 예시 코드들을 살펴 볼 수 있습니다.
차세대 API Mocking 라이브러리 라고 소개하고 있으며, Javascript, TypeScipt 에 따라 친절하게 코드를 보여주며 설명해주고 있네요.

더 자세히 설명을 드리자면,
MSW는 API Mocking 라이브러리로, 서버 방향의 네트워크 요청을 가로채서(intercepter) 모의 응답(Mocked response)을 보내주는 역할을 해냅니다.

그렇기 때문에 따로 Mock 서버를 구축하지 않아도 API 수준의 Mocking을 할 수 있습니다.

MSW가 이러한 역할을 할 수 있는 이유는 Service Worker를 통해 HTTP 요청을 가로채기 때문입니다.

⭐️ 여기서 Service Worker란 ?

Service Worker 는 웹 어플리케이션의 메인 스레드와 분리된 별도의 백그라운드 스레드에서 실행 시킬 수 있는 기술 중 하나 입니다. 이와 같은 특성으로 인해 UI-Block(한번 서버와 통신을 진행할때 그 과정이 끝날때 까지는 사용자가 다른 버튼을 누르지 못하게끔 만드는 일종의 안전 장치) 없이 연산을 처리 할 수 있습니다.

Service Worker는 다음과 같은 기능에 많이 사용되고 있습니다.

  • 네트워크가 원활할 때 동기화를 시켜주는 백 그라운드 동기화 기능이나, 높은 비용의 계산을 처리할 때 또는 푸시 이벤트를 생성할 때 사용
  • MSW의 동작 방식과 관계되어있는, 네트워크 요청을 가로채는 행위를 수행 합니다.

위와 같은 기능에 많이 사용되면서도 반대로 사용이 제한되는 경우도 있습니다,

  • 대부분의 모던 브라우저에서 지원하고 있으나, IE(이미 돌아가신 ☠️) 같은 일부 브라우저에서는 지원하지 않습니다.
  • 기본적으로 localhost가 아닌 환경이라면 HTTPS 보안 프로토콜 환경이 필요합니다.
    위와 같은 환경이 필요한 이유는, 중간에서 네트워크로 연결을 가로채고 조작할 수 있는 아주 강력한 기능을 가지고 있기 때문에, HTTPS가 기본적으로 제공되는 환경에서만 사용할 수 있는 점 명심하시길 바랍니다.

결론적으로, MSW 는 Service Worker를 기반으로 모의 API를 만들어 냅니다.
다른 프론트엔드에서 사용하는 수많은 라이브러리나 프레임워크에 종속적이지 않고 호환성 이슈 없이 동작합니다.

⭐️ 본격적으로 MSW 활용한 개발 방식

위의 그림과 같이 기획자가 요구사항을 전달하면, 프론트엔드 개발자와 백엔드 개발자가 API 스펙을 합의 하고 백엔드 개발자는 프론트 개발자에게 API의 스펙을 제공합니다.

그 이후, 프론트엔드 개발자는 백엔드에 종속적으로 개발을 진행하지 않고, MSW를 통해 네트워크 레벨에서의 Mocking을 진행한 후에 애플리케이션 개발을 진행하게 됩니다.

그리고 이후에 백엔드 개발자가 API를 제공하면, 프론트엔드 개발자는 별다른 작업 없이 MSW를 스위치 오프만 하면 Production으로 배포할 수 있는 형태의 개발 과정을 통해 개발을 진행할 수 있습니다.

📖 MSW 사용방법 들여다보기

✏️ 패키지 설치

먼저 MSW 패키지를 설치 합니다.

$ npm install msw --save-dev
# or
$ yarn add msw --dev

✏️ Service Worker 파일 경로 설정

Service Worker를 제공하기 위해 MSW는 전용 CLI(Command-line Interface) 를 제공합니다.
이 CLI의 Init 명령어와 함께 사용하고자 하는 프로젝트의 public directory를 지정해서 실행해줍니다.

$ npx msw init < PUBLIC_DIR > --save

위에 커맨드라인에 있는 < PUBLIC_DIR > 은 각 사용자의 스펙에 맞게 사용하시면 됩니다.
사용자 스펙에 따른 내용은 공식 문서에서 확인 하실 수 있습니다.

저는 create-react-app 으로 프로젝트를 생성 했기 때문에 경로를 ./public으로 설정하겠습니다.

그러면 public 디렉토리에

JS 파일 하나가 생성된것을 확인할 수 있습니다.

✏️ MSW Handler 생성

생성을 확인한 이 후에는 Mocking할 API를 핸들러를 만들어보겠습니다.

export const handlers = [
  rest.get("api/products", (req, res, ctx) => {
    // 무한스크롤에 필요한 변수 생성
    const { searchParams } = req.url;
    const size = Number(searchParams.get("size"));
    const page = Number(searchParams.get("page"));
    const totalCount = pokemons.length;
    const totalPages = Math.round(totalCount / size);
    // queryString 오류에 따른 에러 코드 반환
    const errorCode = req.url.searchParams.get("error_code");
    if (errorCode) {
      return res(ctx.status(Number(errorCode)));
    }

    // HTTP GET 메서드 + API URL 설정
    return res(
      ctx.status(200), // 응답 상태 설정
      // 응답으로 넘겨줄 Json 데이터
      ctx.json<PaginationResponse>({
        contents: pokemons.slice(page * size, (page + 1) * size),
        pageNumber: page,
        totalPages,
        totalCount,
        isLastPage: totalPages <= page,
        isFirstPage: page === 0,
        pageSize: 0,
      }),
      ctx.delay(3000) // 응답 시간 설정
    );
  }),
];

저는 PokeAPI 를 통해 Mock 데이터를 만들어 사용자에게 응답값으로 보내주고 있습니다.
각자 프로젝트의 사정에 맞게 생성해서 사용하면 됩니다.
이렇게 간단하게 가로챈 네트워크의 요청에 대해서 모의 API 를 생성할 수 있다는 점만 확인하신 후에 넘어가면 됩니다.

✏️ MSW import

그리고 모의 응답을 위한 핸들러를 MSW 에서 사용할 수 있도록 import 합니다.

import { setupWorker } from "msw";
import handlers from "./handlers";

export const worker = setupWorker(...handlers);

✏️ MSW start

그리고 마지막 단계로 MSW를 실행시키기 위한 코드를 추가합니다. 노드 환경 변수에 따라 MSW 를 사용하거ㅣ 위한 분기를 포함해 작성합니다.

// import 말고 require 사용할 것 (node)
if (process.env.NODE_ENV === "development") {
  const { worker } = require("./mocks/browser");
  worker.start();
}

이렇게 간단하게 설정한 이후에 프로젝트에 적용해서 사용하면 됩니다.
제가 이렇게 예시로 든 코드 이외에도 MSW 공식 문서에도 예제가 잘 나와있기 때문에 참고해서 하시면 됩니다.

그리고 이후에 설정한 값들이 정상적으로 동작하는지 확인합니다.

마지막으로 정상적으로 동작하는 것을 메시지로 확인할 수 있었습니다. 큰 어려움이나 공수 없이 기존에 동작하던 프로젝트에도 간편하게 MSW를 적용할 수 있었습니다.

🙏 사용 후기

저는 백엔드에 대한 지식이 전무한 상태에서 프론트엔드 개발 관련한 프로젝트를 진행했습니다. 그리고 API가 준비되어 있지 않은 상태에서도 프로젝트를 빠르게 진행할 수 있었습니다. 저는 MSW를 적용한 무한스크롤 그리고 자동검색을 구현하고 있는 상태인데 API가 구현되지 않은 상태임에도 불구하고 높은 퀄리티를 가진 프로젝트를 완성 시킬 수 있었습니다. 제가 적용한 무한스크롤과 자동검색은 구현, 리팩토링 과정을 다음 블로그 글에서 한번 다뤄 보겠습니다.

🔗 참고

profile
모든 결과는 내가 하기 나름이다 🔥

0개의 댓글