JS & TS/TypeScript

[TypeScript] Spring Boot로 개발한 REST API 프론트엔드에서 연동

Bay Im 2025. 1. 24. 19:46

 
예전엔 프론트 두려워하고 자신도 없었는데요,, 그래도 풀스택 교육 들으면서 React-TypeScript 조합으로 프론트 개발도 해보고, API 연동도 해보니 이제 어느정도는 할 수 있게 되었답니다.
물론 디자인까진 많이 신경을 못쓰지만요..
 
원할한 프론트엔드와의 협업과 백엔드를 맡아도 간단한 프론트 개발할 일이 분명히 있을 것 같아서 까먹지 않도록 API 연동 순서를 정리해봅니다.
React-TypeScript 환경에서 Spring Boot로 개발했던 REST API 연동입니다.
 


 

1. 엔티티별 DTO 타입 정의

 
1-1. 백엔드 API 만들 때 dto 클래스 작성했던 것을 모두 타입 정의를 해줘야 한다.
엔티티클래스명+Request/ReponseDto.d.ts 파일 생성

 
 
1-2. 각 엔티티별로 만들어둔 Request, Response Dto 클래스 필드들을 모두 타입 정의를 해준다.
Request, Response 로만 나눠서 파일 생성하고, 해당 파일안에 모두 작성하면 됨.
 

위에는 Spring Boot dto 클래스들

 

Dto 클래스의 필드들을 타입 정의

 

  • type 종류
    • boolean
    • number
      • 소수점 포함
    • string
      • 작은 따옴표, 큰 따옴표 포함
    • array
      • 다중 타입 가능 (string | number)[]
    • tuple
      • 고정된 길이 배열
    • enum
    • any
      • API 같이 외부 자원을 사용할 때 타입을 단언할 수 없을 경우
    • unknown
    • object
    • null, undefined
    • void
      • 값을 반환하지 않는 함수에서 사용
    • union
      • 2개 이상의 타입을 허용하는 경우 (string | number)
    • function

 
 
 

2. urlFactory.ts에 각 API마다 URL 등록

urlFactory.ts라는 파일은 API를 한눈에 볼 수 있고, 매개변수와 경로를 적어서 Fetch 함수 작성시 사용할 수 있다.
 
2-1. 각 API 별로 URL을 등록한다.
주석으로 HTTP 메소드 종류와 간단한 설명, Req/Res 받는 데이터나 상태 코드에 대해서 적어두면 좋다.
 
예시)

const BASE_URL = import.meta.env.VITE_API_URL;

//--------------- 메인 ---------------//

// POST - 간편 로그인: LoginReqDto -> LoginResDto
export const LoginURL = () => `${BASE_URL}/login`;

//--------------- 모임원 ---------------//

// POST - 모임원 전체 출력: TeamMembersReqDto -> TeamMembersResDto
export const TeamMembersPostURL = () => `${BASE_URL}/team`;

// POST - 모임 초대하기 (초대링크 생성): InviteTeamReqDto -> String
export const GenerateInviteLinkPostURL = () => `${BASE_URL}/team/invite-team`;

// PUT - 총무 변경: ChangeOwnerReqDto -> 200 OK
export const ChangeOwnerPutURL = () => `${BASE_URL}/team/change-owner`;

 

 
 

3. 각 페이지에 Fetch 함수 사용해서 API 연동하기

아마 프론트랑 협업할 때는 useFetch나 모달, 토글 등 이미 작성된 커스텀 Hook이 있을거다. 그 Hook을 사용해서 API 연동작업을 하면 된다.
 
예로 모임원 전체 출력 기능을 연동한다면,
해당 API는 List<TeamMembersResDto> teamMembers(Long teamIdx); 의 형태이다.
team 아이디를 전달하고, ResDto 리스트를 받는 형태이다.
 
3-1. 프론트에서 먼저 전달할 값을 변수로 받는다.
const requestData: TeamMembersReqDto = { teamIdx: teamIdx };
 
3-2. fetch 함수를 사용하여 API 연동 코드를 작성한다.

  // 모임원 전체 정보 가져오기
  const {
    data: teamMemersData,
    isLoading: isTeamMembersLoading,
    refetch,
  } = useFetch<TeamMembersReqDto, TeamMembersResDto[]>(
    TeamMembersPostURL(),
    "POST",
    requestData
  );

Response 받을 데이터는 data: 에 작성하면 된다.
useFetch 함수 부분은 아까 형태처럼 teamIdx를 전달하고(ReqDto), ResDto 리스트를 받는 형태로 작성한다.
그리고 아까 등록한 해당 API에 맞는 URL과 HTTP 방식을 작성해주면 된다.
 
3-3. return 부분에 response된 값을 출력할 코드를 작성한다.

return (
... 생략 ...
<span>{teamMemersData?.length}명 참여 중</span>

... 생략 ...
          <VStack className="w-full gap-4">
            <span className="text-sm"> 총무 </span>
            {teamMemersData?.map(
              (member) =>
                member.teamMemberState === "총무" && (
                  <HStack
                    key={member.teamMemberIdx}
                    className="items-center gap-4"
                  >

Response 받은 데이터를 사용하여 출력할 데이터를 작성하면 된다.
 


 
참고로 커스텀 Hook을 따로 만들어서 쓰지않고, fetch 함수를 썼을땐 이런 형태였답니다.

  // 카테고리 별 메뉴 출력
  const fetchData = () => {
    fetch('<http://localhost:8080/order>', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        category: category,
        page: page,
      }),
    })
      .then((res) => {
        return res.json();
      })
      .then((json) => {
        const message: Message = json;
        const { status, result: products } = message;
        if (status == 'PRODUCT_CHECK_SUCCESS') {
          setProducts(products.content);
          setTotalPage(products.totalPages);
        }
      })
      .catch((err) => console.error(err));
  };

 
fetch 함수 사용하는 것 보단 확실히 커스텀 Hook을 따로 만들어서 사용하는 것이 코드도 줄고 편한 것 같아요.

'JS & TS > TypeScript' 카테고리의 다른 글

[TypeScript] Utility Types  (0) 2024.02.15
[TypeScript] 선언 파일과 구성 및 옵션, 타입 운영  (0) 2024.02.15
[TypeScript] Generic  (0) 2024.02.15
[TypeScript] 타입 제한자  (0) 2024.02.15
[TypeScript] Class  (0) 2024.02.13