Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] MSW 세팅 및 http 통신 헬퍼 함수 추가 #61

Merged
merged 9 commits into from
Aug 2, 2024

Conversation

lybell-art
Copy link
Collaborator

@lybell-art lybell-art commented Aug 1, 2024

#️⃣ 연관 이슈

📝 작업 내용

Mock Service Worker를 세팅했습니다.

서버로 데이터를 불러오는 함수를 좀 더 쉽게 쓰도록 하였습니다.

  • 서버로 무언가를 요청하는 fetchServer 함수를 만들었습니다.
  • 비동기 요청을 React Suspense가 인식하도록 하는 wrapPromise 함수를 만들었습니다.
  • fetchServer 함수와 wrapPromise 함수를 합친 fetchResource 함수를 만들었습니다. 서버로부터 무언가를 받아서 렌더링할 때 씁니다.

MSW 사용 방법

import { http, HttpResponse } from "msw";

const handlers = [
// get 메소드는 다음과 같이 작성하세요. HttpResponse.json 안에 반환할 결과를 넣어줍니다.
  http.get("/api/test", () => {
    return HttpResponse.json([
      { title: "hello, world!" },
      { title: "hi baby!" },
    ]);
  }),
// post 메소드는 다음과 같이 작성하세요. await request.json()으로 클라이언트에서 보낸 body를 json 형식으로 가져올 수 있습니다.
  http.post("/api/post", async ({ request }) => {
    const value = await request.json();
    return HttpResponse.json({ status: "success", data: value });
  }),
// 만약 404 등 오류 상태를 반환해야 한다면, HttpResponse.json의 2번째 인자로 {status: (오류 상태)}를 추가하세요.
// 그 외에도 2번째 인자에 응답 헤더 등을 설정할 수도 있습니다.
  http.get("/api/404", () => {
    return HttpResponse.json({ status: "fail" }, { status: 404 });
  }),
];

export default handlers;

각 기능 폴더에 mock.js 파일을 만들어주세요. mock.js 파일 mock api가 정의된 handler 배열을 만들고, 그 배열을 export해 주세요.
msw 사용법은 공식 문서를 참조하세요.

import { setupWorker } from "msw/browser";
import commentHandler from "./comment/mock.js";

export default setupWorker(...commentHandler);

만드신 mock 배열을 임포트한 뒤, setupWorker에 spread 연산자로 mock 배열을 추가해주시면 됩니다.
정의한 mock api는 dev 서버에서 그냥 fetch 요청으로 받아올 수 있습니다. 따로 빌드할 때 뭘 수정하고 그런건 없어요.

fetch 헬퍼 함수 사용 방법

fetchServer

기본적으로 fetch와 비슷하게 사용할 수 있습니다. 단, method는 소문자도 허용됩니다.

import { useState, useEffect } from "react";
import { fetchServer } from "@/common/fetchServer.js";

function Test()
{
  const [data, setData] = useState(null);
  useEffect( ()=>{
    fetchServer("/api/test").then( data=>setData(data.value) );
  }, [] );

  return <div>{data}</div>
}

아무런 설정 없이 body에 객체를 넣으면 자동으로 json 형태로 보내줍니다.

import { fetchServer } from "@/common/fetchServer.js";

function Test()
{
  const [data, setData] = useState(null);
  const onClick = ()=>{
    fetchServer("/api/test2", {method: "post", body: {data: "hello, world!"}  })
       .then( ()=>console.log("success!") );
  }

  return <div onClick={onClick}>서버로 데이터 보내기</div>
}

fetchServer는 http 응답 코드 4xx, 5xx를 받으면 에러를 뱉습니다. .catch로 에러를 핸들링할 수 있으며, 해당 에러 객체가 HTTPError인지를 체크해서 에러를 핸들링할 수 있습니다.

import { fetchServer, HTTPError } from "@/common/fetchServer.js";

function Test()
{
  const [data, setData] = useState(null);
  const onClick = ()=>{
    fetchServer("/api/test2", {method: "post", body: {data: "hello, world!"}  })
       .then( ()=>console.log("success!") )
       .catch( (error)=>{
         if(error instanceof HTTPError) console.log(error.status);
         else console.log("not an http error!");
       });
  }

  return <div onClick={onClick}>서버로 데이터 보내기</div>
}

fetchResource

import { useMemo } from "react";
import ErrorBoundary from "@/common/errorBoundary.jsx"; 
import Suspense from "@/common/suspense.jsx"; 
import { fetchResource } from "@/common/fetchServer.js";

function TestRenderer({resource})
{
  const data = resource();
  return <div>{data.value}</div>;
}

function Test()
{
  const resource = useMemo( ()=>fetchResource ("/api/test"), [] );

  return <ErrorBoundary fallback={<div>여기에 에러 컴포넌트가 들어감</div>}>
    <Suspense fallback={<div>여기에 로딩 컴포넌트가 들어감</div>}>
      <TestRenderer resource={resource} />
    </Suspense>
  </ErrorBoundary>
}

fetchResource는 서버로부터 데이터를 읽어오는 작업을 더 선언적으로 하도록 합니다.
부모 컴포넌트에서 fetchResource((주소))를 선언해서 이 리소스를 웹에서 읽어오겠다고 선언합니다. useMemo로 감싸면 더 좋습니다.

fetchResource의 값은 함수입니다. 이 함수는 실제 데이터를 렌더링하는 컴포넌트의 props로 넘겨준 뒤, 해당 컴포넌트를 Suspense와 ErrorBoundary로 감싸면 됩니다. Suspense와 ErrorBoundary의 fallback props에는 각각 리소스가 로딩 중일 때, 리소스 불러오는 에러가 생겼을 때 렌더링할 리액트 엘리먼트를 넣으면 됩니다.

실제 데이터를 렌더링하는 컴포넌트는 부모에게서 받아온 resource 함수를 호출해서 실제 데이터를 받아온 뒤, 렌더링을 수행하면 됩니다.

💬 리뷰 요구사항

지금 http 요청하는 래퍼 함수 만들었는데 사용하시기 편하실 것 같으신가요

@lybell-art lybell-art added the feat 기능 구현 label Aug 1, 2024
@lybell-art lybell-art requested a review from darkdulgi August 1, 2024 12:46
@lybell-art lybell-art self-assigned this Aug 1, 2024
@lybell-art lybell-art linked an issue Aug 1, 2024 that may be closed by this pull request
2 tasks
Copy link
Collaborator

@darkdulgi darkdulgi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다!

@darkdulgi darkdulgi merged commit 486bca0 into dev Aug 2, 2024
1 check passed
@lybell-art lybell-art deleted the feature/58-msw branch August 3, 2024 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat 기능 구현
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[feat] MSW 초기 세팅
2 participants