Skip to content

Conversation

@KimKyuHoi
Copy link
Collaborator

@KimKyuHoi KimKyuHoi commented Jan 31, 2025

Pull request

Related issue

Motivation and context

  • fetch를 위한 공용 인스턴스 및 메서드 개발이 필요합니다.
  • fetch 내에서 발생하는 에러코드 정리도 필요합니다.

Solution

  • prettier printWidth 가독성이 너무 구려 180 -> 80으로 변경했습니다.

  • 파일 분리 apis 폴더를 services 폴더명은 변경하였습니다.

    • fsd 구조에 따라 apis, models로 분리하였고 modes는 공용 로직, apis는 인스턴스 및 메서드로 분리하였습니다.
.
├── apis
│   ├── fetch-instance.api.ts
│   ├── fetch-method.api.ts
│   └── index.ts
├── index.ts
└── models
    ├── error
    │   ├── authorization-errors.ts
    │   ├── index.ts
    │   └── workspace-errors.ts
    ├── index.ts
    └── types
        ├── fetch-types.d.ts
        └── index.ts
  • Error Code 작성

에러코드를 전부 객체화 시킨후 객체 리터럴화 시켜 Index.ts에 스프레드 연산자를 적용하여 개발을 진행하였습니다.

import { AUTH_ERROR_MESSAGES } from './authorization-errors';
import { WORKSPACE_ERROR_MESSAGES } from './workspace-errors';

export const ERROR_MESSAGES: Record<string, string> = {
  ...AUTH_ERROR_MESSAGES,
  ...WORKSPACE_ERROR_MESSAGES,
};

에러메시지를 도메인에 맞게 따로 코드를 분리해놨으므로 이후 유지보수에 좋을듯합니다.

  • fetch Instance작성

@handje @Zero-1016 제가 생각나는대로 최대한 예외처리를 하긴 했는데 next를 처음 다뤄보기때문에 추가해주실 내용 있으면 추가하겠습니다.
현재 주석처리를 통해 fetchInstance에 대한 과정을 문서화하였습니다.

  • tsDocs를 통한 타입 문서화
 /**
  /**
   * options 객체에서 필요한 값들을 구조분해할당합니다
   * @template TBody - 요청 본문의 타입
   * @typedef {object} ExtractedOptions
   * @property {TBody} [body] - 요청 본문 데이터
   * @property {Record<string, string>} [params] - URL 쿼리 파라미터
   * @property {RequestCache} [cache] - Next.js 캐시 전략
   * @property {string[]} [tags] - 캐시 무효화 태그
   * @property {number} [revalidate] - 캐시 재검증 시간(초)
   * @property {boolean} [withToken=true] - 토큰을 헤더에 추가할지 여부
   */
  const {
    body,
    params,
    cache,
    tags,
    revalidate,
    withToken = true,
    ...restOptions
  } = options;
  • GET, POST, PATCH, DELETE 공용 메소드 구현
    • tsDocs를 통한 문서화
 /**
* GET 요청을 보내는 함수입니다.
* @template TResponse - 응답 데이터의 타입
* @typedef {object} GetRequestOptions
* @property {Record<string, string>} [params] - URL 쿼리 파라미터
* @property {RequestCache} [cache] - Next.js의 캐시 전략 ('force-cache' | 'no-store' | 'no-cache')
* @property {string[]} [tags] - 캐시 무효화를 위한 태그 배열
* @property {number} [revalidate] - 캐시 재검증 주기(초)
* @property {boolean} [withToken] - 인증 토큰 사용 여부
*
* @param {string} url - API 엔드포인트 URL
* @param {Omit<FetchOptions, 'body'>} [options] - GET 요청 옵션
* @returns {Promise<TResponse>} 응답 데이터를 포함한 Promise
*
* @example
* ```typescript
* // 기본 GET 요청
* const data = await getRequest<UserData>('/api/users/me');
*
* // 쿼리 파라미터와 캐시 옵션과 토큰이 없을때 GET 요청
* const users = await getRequest<User[]>('/api/users', {
*   params: { page: '1', size: '10' },
*   cache: 'force-cache',
*   tags: ['users'],
*   withToken: false,
* });
* ```
*/
export async function getRequest<TResponse>(
 url: string,
 options?: Omit<FetchOptions, 'body'>,
): Promise<TResponse> {
 return fetchInstance<TResponse>(url, 'GET', options);
}

How has this been tested

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the docs/CONTRIBUTING.md document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@KimKyuHoi KimKyuHoi added ✨ Feature 기능 추가 🖥️ FE 프론트엔드 무조건 스프린트내에 해야하는 것들 labels Jan 31, 2025
@KimKyuHoi KimKyuHoi added this to the 주톡피아 마일스톤 1 milestone Jan 31, 2025
@KimKyuHoi KimKyuHoi requested a review from handje January 31, 2025 05:05
@KimKyuHoi KimKyuHoi self-assigned this Jan 31, 2025
@KimKyuHoi KimKyuHoi requested a review from Zero-1016 January 31, 2025 05:53
Copy link

@Zero-1016 Zero-1016 left a comment

Choose a reason for hiding this comment

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

규회님은 주석이나 문서화를 되게 꼼꼼하게 하시는군요 보기 좋습니다. 직접 fetchInstance를 구현하시고 멋지십니다!

궁금한 사항이나, 소소한 TMI 위주로 리뷰를 남겨드려요!

별도로 질문이 있습니다! 배럴 파일을 되게 많이 사용하시는데 경로가 짧아지는 거 이외에 장점이 있나요? 어떤 이점으로 사용하는지 궁금합니다. (ex: fsd 구조이다 보니 폴더 구조가 복잡해서 배럴 파일로 최상단에서 사용)

// withToken이 true일 때만 토큰을 헤더에 추가
if (withToken) {
const token =
typeof window !== 'undefined' ? localStorage.getItem('token') : null;

Choose a reason for hiding this comment

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

withToken 일 때 token이 없다면 의도치 않은 요청이 아닐까요? 에러가 나타나면 좋을 듯합니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오 제가 생각했던 부분은 token을 넣어야할 api와 넣지 말아야할 api를 구분지어서 request를 보내기 위해서 짠 코드긴 했습니다.
저희가 메인 페이지 내에서 주식 데이터를 불러올때 로그인없이도 받아올 수 있다보니 그랬던 것 같습니다 (:

Choose a reason for hiding this comment

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

위에서 봤을 때는 withToken을 명시해야 되는 거 같아서 없다면 에러가 발생해야 하지 않을까라는 생각이 있긴 했네요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오호 뭔가 헷갈릴수도 있겠단 생각이 드네요. 객체명을 바꾸던가 조금 개선을 해야되겠군요

Copy link
Collaborator

Choose a reason for hiding this comment

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

저도 비슷한 생각입니다!
저는 단순하게 생각하여 token이 없다면 에러처리를 해야할것같은데, token을 넣지 말아야할 api는 어떤것이 있을지 궁급합니다!

Copy link
Collaborator

@handje handje Jan 31, 2025

Choose a reason for hiding this comment

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

@KimKyuHoi 그리고 리뷰가 아닌 단순한 궁금증인데, token관련한 코드가 3번 정도 나타나는데 보통 그런식으로 여러번 확인하고 할당하는걸까요?
처음 변수 선언때도 localstorage에서 받아오고 아래 withtoken에 의해 또한번 받아오면서, header를 선언하는 부분도 token의 여부에 따라 달라지는 것이 두번 반복되는것으로 보여서요!
제가 instance는 해본적이 없어서 다 다른 경우에 대응하기 위한 부분일까요?

Copy link
Collaborator Author

@KimKyuHoi KimKyuHoi Feb 1, 2025

Choose a reason for hiding this comment

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

저도 비슷한 생각입니다! 저는 단순하게 생각하여 token이 없다면 에러처리를 해야할것같은데, token을 넣지 말아야할 api는 어떤것이 있을지 궁급합니다!

초기 로그인같은 경우는 토큰없이 쓰기때문에 넣긴 했습니다.

그리고 리뷰가 아닌 단순한 궁금증인데, token관련한 코드가 3번 정도 나타나는데 보통 그런식으로 여러번 확인하고 할당하는걸까요?
처음 변수 선언때도 localstorage에서 받아오고 아래 withtoken에 의해 또한번 받아오면서, header를 선언하는 부분도 token의 여부에 따라 달라지는 것이 두번 반복되는것으로 보여서요!
제가 instance는 해본적이 없어서 다 다른 경우에 대응하기 위한 부분일까요?

그리고 첫번째 토큰 로직은 저희가 스토리지 내에서 토큰을 가지고 오기로 결정했으므로 스토리지에서 토큰을 받아오는 로직입니다.

두번쨰 로직은 저희가 토큰을 쓸껀지 안 쓸껀지 확인하는 로직이구요. default는 true이나 false설정을 걸 경우 토큰을 안 쓸 수 있습니다.

세번째 로직은 가지고 온 토큰을 header내에 Authorization Bearer에 넣는 로직입니다.
제가 로직 관련해서 주석처리를 해놓긴 했는데 나중에 궁금해시면 주석처리한 부분 따라 읽으면서 코드 내려가시면 읽기 편하실껍니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@handje 객체명 교체하였습니다~ withToken -> includedAuthToken으로 교체했습니다~

@KimKyuHoi
Copy link
Collaborator Author

규회님은 주석이나 문서화를 되게 꼼꼼하게 하시는군요 보기 좋습니다. 직접 fetchInstance를 구현하시고 멋지십니다!

궁금한 사항이나, 소소한 TMI 위주로 리뷰를 남겨드려요!

별도로 질문이 있습니다! 배럴 파일을 되게 많이 사용하시는데 경로가 짧아지는 거 이외에 장점이 있나요? 어떤 이점으로 사용하는지 궁금합니다. (ex: fsd 구조이다 보니 폴더 구조가 복잡해서 배럴 파일로 최상단에서 사용)

오호 배럴파일은 쓰는이유는 import문이 간단해지기 때문입니다. fsd를 사용하게 되면 결국엔 3 depth까지 넘어가기 때문에 절대경로를 쓰게 된다면 엄청난 길이의 Import문을 보실 수 있는데 그걸 방지하기 위해 배럴 파일을 넣긴합니다.

@handje
Copy link
Collaborator

handje commented Jan 31, 2025

@Zero-1016 @KimKyuHoi 지형님과 규회님의 엄청난 코드와 리뷰덕에 많이 배우고있습니다!! 멋져용
특히 문서화를 직접 해주시는건 처음봐서 엄청나네요 👍

Copy link
Collaborator

@handje handje left a comment

Choose a reason for hiding this comment

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

좋습니다!

@KimKyuHoi KimKyuHoi merged commit b87c672 into dev Feb 1, 2025
4 of 5 checks passed
@handje handje requested a review from 42inshin February 5, 2025 05:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 추가 무조건 스프린트내에 해야하는 것들 🖥️ FE 프론트엔드

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API Instance 세팅 및 구현

4 participants