Mock Service Worker 기본적 사용법 및 TypeScript 적용하기

Mock Service Worker (이하 MSW) 를 사용하기 위해서 기본적으로 작성해야 할 코드에 대해서는 이전 포스팅에서 작성했다.
이번에는 실제로 MSW 핸들러 코드를 작성하는 법을 작성해보고자 한다.
또 MSW 를 적용하는 것은 쉽지만, 타입스크립트를 적용하는 부분에서 애먹었던 부분이 있었다.
그래서 타입스크립트를 적용하는 방법도 함께 작성해보고자 한다.

handler.ts 작성하기

import { rest } from "msw";

export const handlers = [
	// ...
]

handers.ts 파일은 기본적으로 이렇게 배열의 형태다.
물론 배열이 아니라 한 개의 핸들러만 작성할 수 있지만, 보통은 여러개를 작성할 수 밖에 없기 때문에 배열로 작성하게 된다.

그럼 여기에 실제로 api 모킹 핸들러를 추가해보자


GET 방식

export const handlers = [
	rest.get('/', async (req, res, ctx) => {
		return res(
        	// ...
        )
	}),
]

차근차근 따라가보자
이렇게 하나의 핸들러를 등록할 수 있다. rest 방식과 graphQl 방식 중 나는 더 익숙한 rest 방식으로 진행하겠다.

rest 방식으로 핸들러를 작성한다면, rest 를 쓰고 그 뒤에는 GET, POST, PATCH, DELETE 등의 HTTP 메서드를 붙인다.
Ex) rest.get(), rest.post()

MSW 의 핸들러는 기본적으로 1) 어떤 URL 요청이 들어왔을 때 2) 어떤 동작을 수행할지 로 이루어져있다.
1) 따라서 첫번째 인자는 어떤 URL 로 들어왔을 때를 말하는 URL 경로가 오고,
2) 두번째 인자는 그걸 처리하는 로직이 들어온다.

(Next 환경에서는 '/' 만 적으면 제대로 경로설정이 안되는 문제가 있었다. 왜인지는 모르겠지만.. 그래서 Next 에서는 'http://localhost:3000/' 까지 적어주어야 했다.)


export const handlers = [
	rest.get('/', async (req, res, ctx) => {
      
		return res(
        	ctx.json({
              message: "Welcome to 멋쟁이 토마토처럼🍅",
            })
        )
	}),
]

두번째 인자로 들어오는 콜백함수의 매개변수로는 req, res, ctx 가 온다.
req 는 흔히 말하는 '요청'에 관한 역할을 처리한다.
res 는 응답을 리턴할 때 쓰이는 함수라고 볼 수 있다.
ctx 는 실제로 응답을 어떻게 처리할지 세세한 내용을 정해줄 수 있다.

위의 코드는 '/' 루트 경로로 요청이 들어왔을 때 리턴으로 프로퍼티 키가 message 이고, value 가 Welcome to 멋쟁이 토마토처럼🍅 인 객체를 json 형태로 리턴하겠다는 코드다.

아주아주 간단한 구조다. 이제 저 ctx.json() 코드 안에 내가 원하는 응답을 json 형태로 보내주면 되는 것이다. 배열이 들어갈 수도 있고, 객체가 와도 되고, 바로 어떤 값을 넣어줄 수도 있다.
이 점이 MSW 의 강력한 기능이다.
해당 URL 로 온 요청에 대해서는 내가 의도한 응답을 내려줄 수 있다. 그런데 그것이 기존의 mock data 를 준비해놓고서 프로젝트를 진행하는 것이 아니라, 실제로 api 요청을 보내고 응답을 보내는 과정 속에서 mock data 를 내려주는 것이기 때문에 네트워크 단에서 모킹을 한다는 점이 차이가 있다.
나중에 백엔드에서 api 가 완성이 된다면 (그리고 모킹할 때의 응답과 똑같이 온다면) 별다른 수정 없이 MSW 만 프로젝트에서 제거한다면 그대로 백엔드 코드와 함께 돌아간다는 것이다.


export const handlers = [
	rest.get('/', async (req, res, ctx) => {
      
		return res(
          	ctx.status(200),
          	ctx.delay(2000),
        	ctx.json({
              	message: "Welcome to 멋쟁이 토마토처럼🍅",
            })
        )
	}),
]

그 외에도 상태코드도 커스텀할 수 있고, 비동기 로직처럼 동작하게 하기 위해 약간의 딜레이를 밀리초(ms) 로 추가할 수도 있다.

POST 방식

이번엔 POST 방식이다. 로그인을 예로 들어보자


export const handlers = [
	rest.post('/login', async (req, res, ctx) => {
      const { email, password } = req.body
      
      const finded = uesrs.find(user => user.email === email)
      if (!finded) {
      	return res(
        	ctx.status(401)
        )
      }
      
      return res(
      	ctx.status(200),
        ctx.delay(2000),
        ctx.json({
        	id: finded.id,
          	email: finded.email,
          	name: finded.name,
          	profileImg: finded.profileImg,
        })
      )
		
	}),
]

간단하게 로그인은 이러한 방식으로 처리할 수 있다.
요청을 보내는 부분에서 POST 로 요청을 보낼 때 해당 데이터를 함께 보내게 된다.
위 예시에서는 POST 로 email 과 password 를 보낸다면 핸들러에선 req.body.email, req.body.password 로 꺼내쓸 수 있게 된다.
위의 users 는 로그인 기능 구현을 위해 간단하게 준비한 더미데이터다.
이런 식으로 이메일이 일치하는 이메일이 없다면 에러 상태코드를 내보낼 수도 있고, 로그인이 성공했다면 또 다시 원하는 응답을 내려줄 수 있다.

TypeScript 적용하기

타입스크립트로 MSW 로 작성할 때 req.body 에 들어있는 email 과 password 의 타입을 모르기 때문에 에러를 내보내게 된다. 따라서 이 둘의 타입을 지정해주어야 한다.


interface PostLoginReqBody {
	email: string
  	password: string
}

export const handlers = [
	rest.post<PostLoginReqBody>('/login', async (req, res, ctx) => {
      const { email, password } = req.body
      
      // 이하 동일
	}),
]

이렇게 rest.post 뒤에 제너릭 안에 email 과 password 의 타입을 적어준 인터페이스를 넣어줌으로써 req.body 가 어떤 타입으로 오는지를 명시해준다.
그러면 타입스크립트가 req.body 안에 어떤 데이터와 타입이 오는지를 추론할 수 있다.

params 꺼내기

api 요청을 보내다보면 달라지는 파라미터에 대해서 추출해야할 때가 있다.
가령 아래와 같은 요청이 들어왔다고 치자

export const handlers = [
	rest.get('/:userId', async (req, res, ctx) => {
      const { userId } = req.params
      
      // ...
	}),
]

위에처럼 파라미터로 :userId 가 들어온다고 치면, MSW 의 핸들러 내부에선 req.params.userId 로 꺼내쓸 수 있다.
req.params 의 경우는 타입을 따로 지정해주지 않아도 req.params.파라미터로 온 것들은 모두 문자열로 인식한다.
때문에 params 로 숫자타입을 보내도 문자타입으로 변환되기 때문에 적절히 타입변환을 해서 사용하면 된다.



이상 간단하게 MSW 를 사용하는 법에 대해 알아보았다.
이 정도만 돼도 간단한 api 모킹을 사용하는 데에는 충분히 처리할 수 있다.
그 외에 세세한 부분은 MSW 공식문서 를 확인하면서 적용하면 충분할 것이다.

좋은 웹페이지 즐겨찾기