오늘은 이직을 준비하면서 과제 전형에서 처음 다뤄보았던 msw라는 것을 알아보자.
과제 전형을 받았을때 기초 템플릿과 과제 설명이 들어간 템플릿을 받았는데, 제일 당황했던 부분은 api의 end-point(baseUrl)이 없는것이다. 그래서 계속 제공된 템플릿을 들여다보니 msw라는 것을 발견하게 되었다.
매우 신기했고, 실무에서도 유용하게 쓰일 수도 있을것 같다는 생각이 들었다.
우선 msw를 알아보기 전에 service worker라는 것을 이해하고 넘어가자.
비교적 최근에 도입된 웹 표준 기술로써 브라우저에 들어왔다 나가는 응답과 요청 중간을 감시하여 부가적인 동작을 할 수 있도록 하는 녀석이다.
매우 어려운 개념이다 ㅎㅎ
msw는 mocking service worker의 약자로 말 그대로 service worker를 이용하여 가짜 Api를 mocking 하는 녀석이다.
즉, 브라우저에서 기생하면서 실제 백엔드 처럼 데이터를 건내주고 받는 역활을 한다.
주로, 백엔드 Api의 제작을 진행 중에 프론트 작업을 하기 위해 임시 Api를 만들어서 사용하기도 하고, 테스트시에 훨씬 안정적으로 동작하도록 해준다.
이 msw는 Rest Api, GraphQl을 모두 지원하기 때문에 최근에 매우 주목받고 있는 기술이다.
React + TypeScript
npx create-react-app@latest --template=typescript
msw 설치
npm install -D msw
typeScript를 사용시 의존성 출동이 날 경우 --force 옵션을 추가해서 설치하자!
service worker 등록 코드
npx msw init public/ --save
입력하고 enter를 누르면 public 디렉토리 안에 mockServiceWorker.js라는 폴더가 생신다.
이제 msw를 사용하기 위한 파일은 src 디렉토리안에 mocks라는 디렉토리를 만들어서 넣을 것이다.
// src/mocks/dummy.json
[
{
"id": "123",
"name": "lee",
"country": "ko",
"lang": "react"
},
{
"id": "1234",
"name": "jay",
"country": "eu",
"lang": "vue"
},
{
"id": "12345",
"name": "mark",
"country": "us",
"lang": "spring"
}
]
더미데이터는 실제 Api의 데이터와 형식을 일치 시켜야한다!
// src/mocks/handlers.ts
import { rest } from "msw";
import people from "./dummy.json";
export const handlers = [
rest.get("/people", async (req, res, ctx) => {
await sleep(200);
return res(ctx.status(200), ctx.json(people));
}),
rest.post("/people", async (req, res, ctx) => {
await sleep(200);
people.push({
id: "345",
name: "son",
country: "asia",
lang: "php",
});
return res(ctx.status(201), ctx.json(people));
}),
];
async function sleep(timeout: number) {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
}
get과 post Api를 만들어주었고, 실제 서버처럼 동작하게 보이도록 sleep을 줘보았다.
// src/mocks/browsers.js
import { setupWorker } from "msw";
import { handlers } from "./handlers";
export const worker = setupWorker(...handlers);
브라우저에서 service worker를 사용할 수 있도록 생성해주었다.
// src/index.tsx
if (process.env.NODE_ENV === "development") {
worker.start();
}
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement,
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
현재 실행이 dev모드일 때만 servicer worker를 우리가 만들고 있는 애플리케이션에 삽입해주었다.
axios를 사용해서 데이터를 받아와 볼것이다.
// src/app.tsx
interface ResType {
id: string;
name: string;
country: string;
lang: string;
}
function App() {
const [peopleData, setPeopleData] = useState<ResType[]>([]);
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios({
method: "get",
url: "/people",
});
console.log(res.data);
if (res.status === 200) {
setPeopleData(res.data);
}
} catch (error) {
console.log(error);
}
};
fetchData();
}, []);
return (
<div className="App">
{peopleData.length > 0 ? (
peopleData.map((item) => (
<div key={item.id}>
<p>이름 : {item.name}</p>
<p>나라 : {item.country}</p>
<p>언어 : {item.lang}</p>
</div>
))
) : (
<p>...로딩중</p>
)}
</div>
);
}
실행화면
위의 사진과 같이 실제 Api를 사용하는것과 같이 데이터를 잘 불러오는것을 볼 수 있다.
사진에서는 안보이지만 로딩중에는 로딩중이라는 글씨도 보인다.
이렇게 오늘은 msw에 대해서 알아보았다.
이직 과제전형에서 마주친 새로운 아이였는데, 매우 흥미로워서 한번 적어보았다.
그때는 react-query와 함께 썻었는데 그것과도 매우 잘 호응이 되었다. 매번 개발 할때 마다 백엔드 개발자와 소통하면서 맞춰갔어야 했던 작업을 클라이언트에서 수정해가보면서 개발 할 수 있다는 것이 매우 큰 메리트인것 같다.
사실 이 msw는 test를 위해서 제일 많이 쓰인다.
그래서 다음시간에는 test에서 어떻게 쓰이는지도 한번 알아보도록 하자.