Skip to content

[SWEP-85] 메모장 API tsoa 적용 (#168)#169

Merged
jjiinaaa merged 6 commits intodevelopfrom
refactor/SWEP-85
Feb 10, 2025
Merged

[SWEP-85] 메모장 API tsoa 적용 (#168)#169
jjiinaaa merged 6 commits intodevelopfrom
refactor/SWEP-85

Conversation

@asjasj3964
Copy link
Collaborator

Sweepic Server PR List

close #163

⚒️develop의 최신 커밋을 pull 받았나요?

  • 최신 커밋 업데이트

🔍️ 이 PR을 통해 해결하려는 문제가 무엇인가요?

어떤 기능을 구현한건지, 이슈 대응이라면 어떤 이슈인지 PR이 열리게 된 계기와 목적을 Reviewer 들이 쉽게 이해할 수 있도록 적어 주세요
일감 백로그 링크나 다이어그램, 피그마를 첨부해도 좋아요

  • 메모장의 모든 API tsoa 적용
  • 데이터 조회 시, 해당 사용자의 데이터인지 검사하는 코드 추가
  • 응답은 링크가 구현한 응답 인터페이스로 통일
  • 이미지 업로드 시(@uploadedfile 사용 시) 커스텀한 multer(imageUploader) 이용

✨ 이 PR에서 핵심적으로 변경된 사항은 무엇일까요? (핵심 작업 내용)

문제를 해결하면서 주요하게 변경된 사항들을 적어 주세요

  • 아래와 같이 메모장의 모든 API에 tsoa 적용
    @Route('memo')
    export class MemoFolderController extends Controller {
     ...
      /**
       * 특정 폴더의 사진을 이동하는 API입니다.
       *
       * @summary 사진 이동 API
       * @param req
       * @param currentFolderId 현재 폴더 ID
       * @param body 이동할 폴더 ID, 이동할 사진 배열
       * @returns 성공 시 사진 이동 결과를 반환합니다.
       */
      @Patch('/folders/:folderId/images')
      @Tags('memo-image-controller')
      @Response<ITsoaErrorResponse>(
        StatusCodes.BAD_REQUEST,
        '유효하지 않은 데이터 조회 에러',
        {
          resultType: 'FAIL',
          error: {
            errorCode: 'MEM-400',
            reason: '메모 사진 이동 중 오류가 발생했습니다.',
            data: {
              folderId: '1',
              imageId: ['1'],
            },
          },
          success: null,
        },
      )
      @Response<ITsoaErrorResponse>(
        StatusCodes.NOT_FOUND,
        '존재하지 않은 데이터 조회 에러',
        {
          resultType: 'FAIL',
          error: {
            errorCode: 'FOL-404',
            reason: '해당 폴더를 찾을 수 없습니다.',
            data: {
              folderId: '1',
            },
          },
          success: null,
        },
      )
      @Response<ITsoaErrorResponse>(
        StatusCodes.NOT_FOUND,
        '존재하지 않은 데이터 조회 에러',
        {
          resultType: 'FAIL',
          error: {
            errorCode: 'PHO-404',
            reason: '해당 사진 데이터가 없습니다.',
            data: {
              imageId: '1',
            },
          },
          success: null,
        },
      )
      @SuccessResponse(StatusCodes.OK, '사진 이동 성공 응답')
      @Example({
        resultType: 'SUCCESS',
        error: null,
        success: {
          folderId: '1',
          folderName: 'string',
          imageText: 'string',
          images: [
            {
              imageId: '1',
              imageUrl: 'string',
            },
          ],
        },
      })
      public async handlerMemoImageMove(
        @Request() req: ExpressRequest,
        @Path('folderId') currentFolderId: string,
        @Body() body: BodyToMemoImagesToMove,
      ): Promise<ITsoaSuccessResponse<MemoTextImageListResponseDto>> {
        try {
          const userId = BigInt(req.user!.id);
          const folderId = BigInt(currentFolderId);
          const memoImagesToMove = await memoImagesMove(
            userId,
            folderId,
            bodyToMemoImagesToMove(body),
          );
          return new TsoaSuccessResponse(memoImagesToMove);
        } catch (error) {
          throw error;
        }
      }
      ...
    }
    
    • API에 대한 간략 설명, 각 파라미터 및 body에 대한 설명, 특정 에러 코드에 대해 여러 예제 등을 표시하였습니다. (이전 스웨거 작성한 것과 비슷하게)
  • API 전체적으로 데이터를 조회할 때 사용자 id와도 일치하는 지 검사하는 코드를 추가하여 확실한 데이터를 조회할 수 있도록 하였습니다.
    export const memoImageAdd = async (
      folderId: bigint,
      imageUrl: string,
      userId: bigint,
    ): Promise<MemoFolderImageResponseDto> => {
      const folder = await getMemoFolder(folderId);
      if (folder === null || folder.userId !== userId) { // 로그인한 사용자의 데이터인지 확인
        throw new FolderNotFoundError({folderId});
      }
      ...
    
    • 이는 API 테스트를 할 경우 더 정확한 응답을 주기 위해 추가하였습니다.
  • @uploadedfile() 데코레이터를 이용해 이미지 업로드 시 multer(파일 업로드를 처리하는 미들웨어)를 이전에 구현해 둔 imageUploader(이미지를 받아 S3에 저장하는 커스텀 multer 함수)를 사용하도록 해주었습니다.
    1. 먼저 @uploadedfile()를 이용해 image라는 이름의 파일 객체를 받습니다.
    // src/controllers/tsoa.memo-folder.controller.ts
    
      public async handlerMemoFolderImageAdd(
        @Request() req: ExpressRequest,
        @FormField() folderName: string,
        @UploadedFile() image: Express.MulterS3File,
      ): Promise<ITsoaSuccessResponse<MemoFolderImageResponseDto>> {
        try {
          const userId = BigInt(req.user!.id);
          if (!image) {
            throw new PhotoValidationError({reason: '저장할 사진이 없습니다.'});
          }
          const imageUrl = image.key;
          const folderId = req.uploadDirectory;
          const memoFolderImage = await memoFolderImageCreate(
            userId,
            folderId,
            imageUrl,
            folderName,
          );
          return new TsoaSuccessResponse(memoFolderImage);
        } catch (error) {
          throw error;
        }
      }
    
    1. 그 다음에 yarn tsoa routes -c ./config/tsoa.json를 실행해 라우터를 정의해줍니다. 이 과정을 건너뛰고 multer를 커스텀한 imageUploader multer로 설정할 경우 에러가 발생합니다.
    2. 옵션 객체로 {multer: imageUploader}를 추가하여 특정 API 엔드포인트에서 multer 미들웨어를 활용하여 파일 업로드를 처리할 수 있도록 설정해줍니다.
    // src/app.ts
    ...
    RegisterRoutes(app, {multer: imageUploader});
    ...
    
  • 이전에 tsoa를 적용하지 않고 구현한 api들은 엔드포인트 마지막에 '/not-tsoa'를 붙여 구분하도록 하였습니다.

🤚 동작 확인

기능을 실행했을 때 정상 동작하는지 여부를 확인하고 스크린 샷을 올려주세요

🔖 핵심 변경 사항 외에 추가적으로 변경된 부분이 있나요?

없으면 "없음" 이라고 기재해 주세요

  • Tsoa는 bigint를 인식하지 못해서 request body로 데이터를 전달할 때 id에 해당하는 데이터들의 타입을 bigint에서 string으로 수정하였습니다. 프론트 쪽에서 이미 연동한 api가 있을 수 있으니 프론트분들께 따로 말씀드리겠습니다.
  • 안드로이드는 DELETE 메서드가 일반적으로 Request Body를 지원하지 않기 때문에 Request Body에서 1개 이상의 사진들을 배열로 받아 삭제하는 사진 삭제 API는 POST 메서드로 변경해주었습니다.

🙏 Reviewer 분들이 이런 부분을 신경써서 봐 주시면 좋겠어요

개발 과정에서 다른 분들의 의견은 어떠한지 궁금했거나 크로스 체크가 필요하다고 느껴진 코드가 있다면 남겨주세요

  • tsoa 적용한 API 중에서 누락된 설정이 없는지 확인해주시면 감사하겠습니다.

🩺 이 PR에서 테스트 혹은 검증이 필요한 부분이 있을까요?

테스트가 필요한 항목이나 테스트 코드가 추가되었다면 함께 적어주세요

  • 없음

📌 PR 진행 시 이러한 점들을 참고해 주세요

  • Reviewer 분들은 코드 리뷰 시 좋은 코드의 방향을 제시하되, 코드 수정을 강제하지 말아 주세요.
  • Reviewer 분들은 좋은 코드를 발견한 경우, 칭찬과 격려를 아끼지 말아 주세요.
  • Review는 특수한 케이스가 아니면 Reviewer로 지정된 시점 기준으로 2일 이내에 진행해 주세요.
  • Comment 작성 시 Prefix로 P1, P2, P3 를 적어 주시면 Assignee가 보다 명확하게 Comment에 대해 대응할 수 있어요
    • P1 : 꼭 반영해 주세요 (Request Changes) - 이슈가 발생하거나 취약점이 발견되는 케이스 등
    • P2 : 반영을 적극적으로 고려해 주시면 좋을 것 같아요 (Comment)
    • P3 : 이런 방법도 있을 것 같아요~ 등의 사소한 의견입니다 (Chore)


📝 Assignee를 위한 CheckList

  • To-Do Item

@asjasj3964 asjasj3964 added the ♻️ REFACTOR 기능 향상 및 리팩토링 label Feb 9, 2025
@asjasj3964 asjasj3964 self-assigned this Feb 9, 2025
@asjasj3964 asjasj3964 linked an issue Feb 9, 2025 that may be closed by this pull request
asjasj3964 and others added 5 commits February 9, 2025 17:54
* [SWEP-85] 메모장 API tsoa 적용

* [SWEP-85] 사진 저장하기 전에 존재하는 폴더인지 검사
* [SWEP-85] 메모장 API tsoa 적용

* [SWEP-85] 사진 저장하기 전에 존재하는 폴더인지 검사

* [SWEP-85] 검색어가 빈 문자열이거나 공백만 입력될 경우 에러 처리
@jjiinaaa jjiinaaa merged commit 01137c6 into develop Feb 10, 2025
1 check passed
@jjiinaaa jjiinaaa deleted the refactor/SWEP-85 branch February 10, 2025 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♻️ REFACTOR 기능 향상 및 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SWEP-85] 메모장 API tsoa 적용

2 participants