Super Kawaii Cute Cat Kaoani
본문 바로가기
🏃‍♀️ 대외활동/UMC 7기 - Node.js

[UMC 7th Server] Chapter 8. 프론트엔드 연동과 Swagger

by wonee1 2024. 11. 18.
728x90

Chapter 8. 프론트엔드 연동과 Swagger

 

 

☑️ 실습 인증


 

💼  Swagger 설정하기

 

더보기

👉 Swagger 관련 라이브러리 설치

 

 

다음 명령어들을 입력하여 라이브러리를 설치해줬습니다.

npm add \\
  swagger-autogen \\
  swagger-ui-express

 

 

 

 

👉 Swagger 세팅

 

 

다음과 같이 index.js를 설정해줬습니다.

// src/index.js
import express from "express";
import cors from "cors";
import swaggerAutogen from "swagger-autogen";
import swaggerUiExpress from "swagger-ui-express";
import { handleStoreSignUp,handleListStoreReviews} from "./controller/store.controller.js";
import { handleReviewSignUp } from "./controller/review.controller.js";
import { handleMissionSignUp,handleListStoreMissions,handleListUserInProgressMissions,handleCompleteUserMission   } from "./controller/mission.controller.js";
import { handleChallengeSignUp } from "./controller/challenge.controller.js";
import { handleListUserReviews } from './controller/user.controller.js';

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());
app.use(cors());

app.use((req, res, next) => {
    res.success = (success) => {
      return res.json({ resultType: "SUCCESS", error: null, success });
    };
  
    res.error = ({ errorCode = "unknown", reason = null, data = null }) => {
      return res.json({
        resultType: "FAIL",
        error: { errorCode, reason, data },
        success: null,
      });
    };
  
    next();
});
  
app.use(
  "/docs",
  swaggerUiExpress.serve,
  swaggerUiExpress.setup({}, {
    swaggerOptions: {
      url: "/openapi.json",
    },
  })
);

app.get("/openapi.json", async (req, res, next) => {
  // #swagger.ignore = true
  const options = {
    openapi: "3.0.0",
    disableLogs: true,
    writeOutputFile: false,
  };
  const outputFile = "/dev/null"; // 파일 출력은 사용하지 않습니다.
  const routes = ["./src/index.js"];
  const doc = {
    info: {
      title: "UMC 7th",
      description: "UMC 7th Node.js 테스트 프로젝트입니다.",
    },
    host: "localhost:3000",
  };

  const result = await swaggerAutogen(options)(outputFile, routes, doc);
  res.json(result ? result.data : null);
});

// 가게 추가 API
app.post("/api/stores", handleStoreSignUp);

// 가게 리뷰 추가 API
app.post("/api/reviews", handleReviewSignUp);

// 가게 미션 추가 API
app.post("/api/missions", handleMissionSignUp);

// 가게의 미션 도전하기 API
app.post("/api/challenges", handleChallengeSignUp);

// 리뷰 목록 확인 
app.get("/api/stores/:storeId/reviews", handleListStoreReviews)

// 내가 작성한 리뷰 목록 확인 
app.get('/api/users/:userId/reviews', handleListUserReviews);

// 특정 가게의 미션 목록 조회 API
app.get('/api/stores/:storeId/missions', handleListStoreMissions);

// 특정 사용자의 진행 중인 미션 목록 조회 API
app.get('/api/users/:userId/missions/in-progress', handleListUserInProgressMissions);

// 특정 사용자의 진행 중인 미션 완료로 업데이트 API
app.put('/api/users/:userId/missions/:missionId/complete', handleCompleteUserMission);

app.use((err, req, res, next) => {
    if (res.headersSent) {
      return next(err);
    }
  
    res.status(err.statusCode || 500).error({
      errorCode: err.errorCode || "unknown",
      reason: err.reason || err.message || null,
      data: err.data || null,
    });
  
});

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

 

 

/docs 경로로 들어가서 다음과 같이 swagger가 실행되는 것을 확인했습니다.

 

 

 

👉Swagger 확인하기

 

다음과 같이 swagger로 body 부분을 확인할 수 있었습니다.

 

 

 


 

 

🎯핵심 키워드 정리


 

 

 

💠Swagger란?

  • RESTful API를 설계하고 문서화하기 위한 도구 모음
  • API의 엔드포인트, 요청/응답 구조, 파라미터 등을 YAML이나 JSON 형식으로 작성해 인터랙티브한 문서를 자동 생성한다.
  • 클라이언트나 다른 개발자와 더 쉽게 협업할 수 있게 도와준다
  •  

💠 OpenAPI

  • RESTful API를 설계하고 문서화하기 위한 표준화된 사양
  • API의 구조와 동작 방식을 정의하기 위해 YAML이나 JSON 형식을 사용하며, 이를 통해 API 문서를 자동 생성하고, 개발 및 유지보수를 간편하게한다.

 

💠 OpenAPI 버전 별 특징 및 주요 차이점

 

2.0 기본적인 REST API 구조와 보안 정의 지원 Swagger에서 OpenAPI로의 전환점
3.0 components, oneOf/anyOf, 다중 파일 업로드, 헤더 인증 문서화 유연성 증가
3.1 JSON Schema 호환성, webhooks, 비동기 처리 지원 최신 JSON 표준 및 비동기 지원 강화

 

 

 

💠 OpenAPI Component

components:
  schemas:공통 데이터 모델 (예: User, Product 등)을 정의하여 여러 곳에서 재사용 가능
   
  
  parameters:공통 파라미터 (예: userId, storeId 등)를 정의해 여러 경로에서 재사용

  securitySchemes:인증 방식 (API Key, OAuth 등)을 정의해 여러 엔드포인트에서 일관된 인증 처리

  requestBodies:
 
  responses:자주 쓰이는 응답 (예: 404 Not Found, 500 Internal Server Error 등)을 미리 정의
  
  headers: API 요청이나 응답에 공통으로 사용되는 헤더를 정

  examples: 요청과 응답의 예시 데이터를 정의해 개발자가 요청이나 응답 구조를 쉽게 이해할 수 있게한다
    
  links: API 응답을 기반으로 다른 관련된 API로 연결할 때 사용할 수 있다
   
  callbacks: 비동기 API에서 콜백 URL을 정의하여 서버가 작업 완료 후 클라이언트에 알림을 보낼 수 있다

 

 

 


 

 

✏️8주차 필기 


 

 

 


 

 

 

 

🔥 미션 인증


 

 

💻 Swagger 문서

 

더보기

 

💠전체적인 결과

 

다음과 같이 나눠주었습니다 (크게 Store, Reviews, Missons ,Challenge, Users)

 

 

 

 

1. review 수정

 

review.controller 수정

import { StatusCodes } from "http-status-codes";
import { bodyToReview } from "../dtos/review.dto.js";
import { reviewSignUp } from "../services/review.service.js";

export const handleReviewSignUp = async (req, res, next) => {
  
  /*
  #swagger.summary = '리뷰 작성 API';
  #swagger.description = '사용자가 특정 상점에 리뷰를 작성하는 API입니다.';
  #swagger.tags = ['Reviews'];
  #swagger.requestBody = {
    description: '리뷰 등록을 위한 요청 데이터',
    required: true,
    content: {
      "application/json": {
        schema: {
          type: "object",
          properties: {
            userId: {
              type: "integer",
              description: "리뷰를 작성하는 사용자의 ID",
              example: 1
            },
            storeId: {
              type: "integer",
              description: "리뷰가 작성될 상점의 ID",
              example: 1
            },
            rating: {
              type: "integer",
              description: "상점에 대한 평점 (1~5 사이의 값)",
              example: 5
            },
            reviewText: {
              type: "string",
              description: "리뷰 내용",
              example: "Amazing coffee and cozy atmosphere!"
            }
          }
        }
      }
    }
  };
  #swagger.responses[201] = {
    description: "리뷰 등록 성공",
    content: {
      "application/json": {
        schema: {
          type: "object",
          properties: {
            resultType: { type: "string", example: "SUCCESS" },
            error: { type: "object", nullable: true, example: null },
            success: {
              type: "object",
              properties: {
                reviewId: { type: "integer", example: 1 },
                userId: { type: "integer", example: 1 },
                storeId: { type: "integer", example: 1 },
                rating: { type: "integer", example: 5 },
                reviewText: { type: "string", example: "Amazing coffee and cozy atmosphere!" },
                createdAt: { type: "string", format: "date-time", example: "2024-10-28T13:01:39.000Z" },
                store: {
                  type: "object",
                  properties: {
                    storeName: { type: "string", example: "Test Store" }
                  }
                }
              }
            }
          }
        }
      }
    }
  };
  #swagger.responses[400] = {
    description: "잘못된 요청 데이터",
    content: {
      "application/json": {
        schema: {
          type: "object",
          properties: {
            resultType: { type: "string", example: "FAIL" },
            error: { type: "string", example: "Invalid request data" }
          }
        }
      }
    }
  };
  #swagger.responses[500] = {
    description: "서버 오류",
    content: {
      "application/json": {
        schema: {
          type: "object",
          properties: {
            resultType: { type: "string", example: "ERROR" },
            error: { type: "string", example: "Internal server error" }
          }
        }
      }
    }
  };
*/
  
  try {
    const review = await reviewSignUp(bodyToReview(req.body));
    res.status(StatusCodes.CREATED).success(review);
  } catch (error) {
    next(error);
  }
};

 

 

✏️결과

 

 

 

 

2. Store 수정

 

store.controller 수정

import { StatusCodes } from "http-status-codes";
import { bodyToStore } from "../dtos/store.dto.js";
import { storeSignUp, listStoreReviews } from "../services/store.service.js";

export const handleStoreSignUp = async (req, res, next) => {
  /*
    #swagger.summary = '상점 등록 API';
    #swagger.description = '새로운 상점을 등록하는 API입니다.';
    #swagger.tags = ['Stores'];
    #swagger.requestBody = {
      description: '상점 등록에 필요한 데이터',
      required: true,
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              storeName: { type: "string", description: "상점 이름", example: "Awesome Cafe" },
              address: { type: "string", description: "상점 주소", example: "123 Coffee Street" },
              regionId: { type: "integer", description: "지역 ID", example: 1 }
            }
          }
        }
      }
    };
    #swagger.responses[201] = {
      description: "상점 등록 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              error: { type: "object", nullable: true, example: null },
              success: {
                type: "object",
                properties: {
                  storeId: { type: "integer", example: 1 },
                  storeName: { type: "string", example: "Awesome Cafe" },
                  address: { type: "string", example: "123 Coffee Street" },
                  regionId: { type: "integer", example: 1 },
                  createdAt: { type: "string", format: "date-time", example: "2024-10-28T13:01:39.000Z" }
                }
              }
            }
          }
        }
      }
    };
    #swagger.responses[400] = {
      description: "잘못된 요청 데이터",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "FAIL" },
              error: { type: "string", example: "Invalid request data" }
            }
          }
        }
      }
    };
  */
  try {
    const store = await storeSignUp(bodyToStore(req.body));
    res.status(StatusCodes.CREATED).success(store);
  } catch (error) {
    next(error); // 전역 오류 핸들러로 오류 전달
  }
};

export const handleListStoreReviews = async (req, res, next) => {
  /*
    #swagger.summary = '상점 리뷰 목록 조회 API';
    #swagger.description = '특정 상점의 리뷰 목록을 조회하는 API입니다.';
    #swagger.tags = ['Stores'];
    #swagger.parameters['storeId'] = {
      in: 'path',
      description: '조회할 상점의 ID',
      required: true,
      schema: {
        type: 'integer',
        example: 1
      }
    };
    #swagger.parameters['cursor'] = {
      in: 'query',
      description: '페이지네이션을 위한 커서',
      required: false,
      schema: {
        type: 'integer',
        example: 0
      }
    };
    #swagger.responses[200] = {
      description: "리뷰 목록 조회 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              error: { type: "object", nullable: true, example: null },
              success: {
                type: "object",
                properties: {
                  data: {
                    type: "array",
                    items: {
                      type: "object",
                      properties: {
                        reviewId: { type: "integer", example: 1 },
                        userId: { type: "integer", example: 1 },
                        storeId: { type: "integer", example: 1 },
                        rating: { type: "integer", example: 5 },
                        reviewText: { type: "string", example: "Great place!" },
                        createdAt: { type: "string", format: "date-time", example: "2024-10-28T13:01:39.000Z" },
                        user: {
                          type: "object",
                          properties: {
                            userName: { type: "string", example: "testuser1" },
                            email: { type: "string", example: "testuser1@example.com" },
                            gender: { type: "string", example: "남성" },
                            birth: { type: "string", format: "date", example: "1990-01-01T00:00:00.000Z" },
                            address: { type: "string", example: "Seoul, South Korea" },
                            detailAddress: { type: "string", example: "101-202" },
                            phoneNumber: { type: "string", example: "010-1234-5678" }
                          }
                        },
                        store: {
                          type: "object",
                          properties: {
                            storeName: { type: "string", example: "Test Store" }
                          }
                        }
                      }
                    }
                  },
                  pagination: {
                    type: "object",
                    properties: {
                      cursor: { type: "integer", nullable: true, example: 4 }
                    }
                  }
                }
              }
            }
          }
        }
      }
    };
    #swagger.responses[400] = {
      description: "잘못된 요청 데이터",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "FAIL" },
              error: { type: "string", example: "Invalid storeId" }
            }
          }
        }
      }
    };
  */
  try {
    const storeId = parseInt(req.params.storeId, 10);
    const cursor = req.query.cursor ? parseInt(req.query.cursor, 10) : 0;
    const reviews = await listStoreReviews(storeId, cursor);
    res.status(StatusCodes.OK).success(reviews);
  } catch (error) {
    next(error);
  }
};

 

 

 

✏️결과

 

 

 

 

 

3. Misson 수정

 

mission controller

import { StatusCodes } from "http-status-codes";
import {
  missionSignUp,
  listStoreMissions,
  listUserInProgressMissions,
  markMissionAsCompleted
} from "../services/mission.service.js";
import { bodyToMission } from "../dtos/mission.dto.js";

export const handleMissionSignUp = async (req, res, next) => {
  /*
    #swagger.summary = '미션 등록 API';
    #swagger.description = '새로운 미션을 등록하는 API입니다.';
    #swagger.tags = ['Missions'];
    #swagger.requestBody = {
      description: '미션 등록에 필요한 데이터',
      required: true,
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              regionId: { type: "integer", description: "지역 ID", example: 1 },
              missionStatus: { type: "string", description: "미션 상태", example: "IN_PROGRESS" },
              description: { type: "string", description: "미션 설명", example: "Discover Seoul's best coffee shops" }
            }
          }
        }
      }
    };
    #swagger.responses[201] = {
      description: "미션 등록 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              success: {
                type: "object",
                properties: {
                  missionId: { type: "integer", example: 1 },
                  regionId: { type: "integer", example: 1 },
                  missionStatus: { type: "string", example: "IN_PROGRESS" },
                  description: { type: "string", example: "Discover Seoul's best coffee shops" },
                  createdAt: { type: "string", format: "date-time", example: "2024-10-28T13:01:39.000Z" }
                }
              }
            }
          }
        }
      }
    };
  */
  try {
    const mission = await missionSignUp(bodyToMission(req.body));
    res.status(StatusCodes.CREATED).success(mission);
  } catch (error) {
    next(error);
  }
};

export const handleListStoreMissions = async (req, res, next) => {
  /*
    #swagger.summary = '상점 미션 목록 조회 API';
    #swagger.description = '특정 상점에서 진행 중인 미션 목록을 조회합니다.';
    #swagger.tags = ['Missions'];
    #swagger.parameters['storeId'] = {
      in: 'path',
      description: '조회할 상점의 ID',
      required: true,
      schema: { type: 'integer', example: 1 }
    };
    #swagger.parameters['cursor'] = {
      in: 'query',
      description: '페이지네이션 커서',
      required: false,
      schema: { type: 'integer', example: 0 }
    };
    #swagger.responses[200] = {
      description: "미션 목록 조회 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              success: {
                type: "array",
                items: {
                  type: "object",
                  properties: {
                    missionId: { type: "integer", example: 1 },
                    title: { type: "string", example: "첫 번째 미션" },
                    description: { type: "string", example: "미션 설명" },
                    pointsReward: { type: "integer", example: 100 }
                  }
                }
              }
            }
          }
        }
      }
    };
  */
  try {
    const storeId = parseInt(req.params.storeId, 10);
    const cursor = req.query.cursor ? parseInt(req.query.cursor, 10) : 0;
    const missions = await listStoreMissions(storeId, cursor);
    res.status(StatusCodes.OK).success(missions);
  } catch (error) {
    next(error);
  }
};

export const handleListUserInProgressMissions = async (req, res, next) => {
  /*
    #swagger.summary = '진행 중인 사용자 미션 목록 조회 API';
    #swagger.description = '사용자가 진행 중인 미션의 목록을 조회합니다.';
    #swagger.tags = ['Missions'];
    #swagger.parameters['userId'] = {
      in: 'path',
      description: '사용자 ID',
      required: true,
      schema: { type: 'integer', example: 1 }
    };
    #swagger.parameters['cursor'] = {
      in: 'query',
      description: '페이지네이션 커서',
      required: false,
      schema: { type: 'integer', example: 0 }
    };
    #swagger.responses[200] = {
      description: "진행 중인 미션 목록 조회 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              success: {
                type: "array",
                items: {
                  type: "object",
                  properties: {
                    missionId: { type: "integer", example: 1 },
                    status: { type: "string", example: "IN_PROGRESS" },
                    description: { type: "string", example: "Discover Seoul's best coffee shops" }
                  }
                }
              }
            }
          }
        }
      }
    };
  */
  try {
    const userId = parseInt(req.params.userId, 10);
    const cursor = req.query.cursor ? parseInt(req.query.cursor, 10) : 0;
    const missions = await listUserInProgressMissions(userId, cursor);
    res.status(StatusCodes.OK).success(missions);
  } catch (error) {
    next(error);
  }
};

export const handleCompleteUserMission = async (req, res, next) => {
  /*
    #swagger.summary = '사용자 미션 완료 API';
    #swagger.description = '사용자가 진행 중인 미션을 완료 상태로 변경합니다.';
    #swagger.tags = ['Missions'];
    #swagger.parameters['userId'] = {
      in: 'path',
      description: '사용자 ID',
      required: true,
      schema: { type: 'integer', example: 1 }
    };
    #swagger.parameters['missionId'] = {
      in: 'path',
      description: '완료할 미션 ID',
      required: true,
      schema: { type: 'integer', example: 1 }
    };
    #swagger.responses[200] = {
      description: "미션 완료 처리 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              success: {
                type: "object",
                properties: {
                  missionId: { type: "integer", example: 1 },
                  userId: { type: "integer", example: 1 },
                  status: { type: "string", example: "COMPLETED" }
                }
              }
            }
          }
        }
      }
    };
  */
  try {
    const userId = parseInt(req.params.userId, 10);
    const missionId = parseInt(req.params.missionId, 10);

    const result = await markMissionAsCompleted(userId, missionId);
    res.status(StatusCodes.OK).success(result);
  } catch (error) {
    next(error);
  }
};

 

 

 

✏️결과

 

 

 

 

 

 

 

 

4. Challenge 수정

 

challenge.controller

import { StatusCodes } from "http-status-codes";
import { bodyToChallenge } from "../dtos/challenge.dto.js";
import { challengeSignUp } from "../services/challenge.service.js";

export const handleChallengeSignUp = async (req, res, next) => {
  /*
    #swagger.summary = '챌린지 등록 API';
    #swagger.description = '새로운 챌린지를 등록하는 API입니다.';
    #swagger.tags = ['Challenges'];
    #swagger.requestBody = {
      description: '챌린지 등록에 필요한 데이터',
      required: true,
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              userId: { type: "integer", description: "사용자 ID", example: 1 },
              missionId: { type: "integer", description: "미션 ID", example: 1 },
              storeId: { type: "integer", description: "상점 ID", example: 1 },
              status: { type: "string", description: "챌린지 상태", example: "IN_PROGRESS" }
            }
          }
        }
      }
    };
    #swagger.responses[201] = {
      description: "챌린지 등록 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              success: {
                type: "object",
                properties: {
                  challengeId: { type: "integer", example: 1 },
                  userId: { type: "integer", example: 1 },
                  missionId: { type: "integer", example: 1 },
                  storeId: { type: "integer", example: 1 },
                  status: { type: "string", example: "IN_PROGRESS" },
                  createdAt: { type: "string", format: "date-time", example: "2024-10-28T13:01:39.000Z" }
                }
              }
            }
          }
        }
      }
    };
    #swagger.responses[400] = {
      description: "잘못된 요청 데이터",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "FAIL" },
              error: { type: "string", example: "Invalid request data" }
            }
          }
        }
      }
    };
    #swagger.responses[500] = {
      description: "서버 오류",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "ERROR" },
              error: { type: "string", example: "Internal server error" }
            }
          }
        }
      }
    };
  */
  try {
    const challenge = await challengeSignUp(bodyToChallenge(req.body));
    res.status(StatusCodes.CREATED).success(challenge);
  } catch (error) {
    next(error);
  }
};

 

 

 

✏️결과

 

 

 

5. Users 수정

 

user.controller

import { StatusCodes } from "http-status-codes";
import { bodyToUser } from "../dtos/user.dto.js";
import { userSignUp, listUserReviews } from "../services/user.service.js";

export const handleUserSignUp = async (req, res, next) => {
  /*
    #swagger.summary = '사용자 회원가입 API';
    #swagger.description = '새로운 사용자를 등록하는 API입니다.';
    #swagger.tags = ['Users'];
    #swagger.requestBody = {
      description: '사용자 회원가입에 필요한 데이터',
      required: true,
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              userName: { type: "string", description: "사용자 이름", example: "John Doe" },
              email: { type: "string", description: "사용자 이메일", example: "johndoe@example.com" },
              password: { type: "string", description: "사용자 비밀번호", example: "password123" },
              gender: { type: "string", description: "성별", example: "남성" },
              birth: { type: "string", format: "date", description: "생년월일", example: "1990-01-01" },
              address: { type: "string", description: "주소", example: "Seoul, South Korea" },
              phoneNumber: { type: "string", description: "전화번호", example: "010-1234-5678" }
            }
          }
        }
      }
    };
    #swagger.responses[200] = {
      description: "사용자 회원가입 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              success: {
                type: "object",
                properties: {
                  userId: { type: "integer", example: 1 },
                  userName: { type: "string", example: "John Doe" },
                  email: { type: "string", example: "johndoe@example.com" },
                  createdAt: { type: "string", format: "date-time", example: "2024-10-28T13:01:39.000Z" }
                }
              }
            }
          }
        }
      }
    };
    #swagger.responses[400] = {
      description: "잘못된 요청 데이터",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "FAIL" },
              error: { type: "string", example: "Invalid request data" }
            }
          }
        }
      }
    };
    #swagger.responses[500] = {
      description: "서버 오류",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "ERROR" },
              error: { type: "string", example: "Internal server error" }
            }
          }
        }
      }
    };
  */
  try {
    const user = await userSignUp(bodyToUser(req.body));
    res.status(StatusCodes.OK).success(user);
  } catch (error) {
    next(error);
  }
};

export const handleListUserReviews = async (req, res, next) => {
  /*
    #swagger.summary = '사용자 리뷰 목록 조회 API';
    #swagger.description = '특정 사용자가 작성한 리뷰 목록을 조회하는 API입니다.';
    #swagger.tags = ['Users'];
    #swagger.parameters['userId'] = {
      in: 'path',
      description: '조회할 사용자 ID',
      required: true,
      schema: { type: 'integer', example: 1 }
    };
    #swagger.parameters['cursor'] = {
      in: 'query',
      description: '페이지네이션을 위한 커서',
      required: false,
      schema: { type: 'integer', example: 0 }
    };
    #swagger.responses[200] = {
      description: "리뷰 목록 조회 성공",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "SUCCESS" },
              success: {
                type: "array",
                items: {
                  type: "object",
                  properties: {
                    reviewId: { type: "integer", example: 1 },
                    storeId: { type: "integer", example: 1 },
                    rating: { type: "integer", example: 5 },
                    reviewText: { type: "string", example: "Amazing coffee and cozy atmosphere!" },
                    createdAt: { type: "string", format: "date-time", example: "2024-10-28T13:01:39.000Z" },
                    store: {
                      type: "object",
                      properties: {
                        storeName: { type: "string", example: "Test Store" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    };
    #swagger.responses[400] = {
      description: "잘못된 요청 데이터",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "FAIL" },
              error: { type: "string", example: "Invalid userId" }
            }
          }
        }
      }
    };
    #swagger.responses[500] = {
      description: "서버 오류",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              resultType: { type: "string", example: "ERROR" },
              error: { type: "string", example: "Internal server error" }
            }
          }
        }
      }
    };
  */
  try {
    const userId = parseInt(req.params.userId, 10);
    const cursor = req.query.cursor ? parseInt(req.query.cursor, 10) : 0;
    const reviews = await listUserReviews(userId, cursor);
    res.status(StatusCodes.OK).success(reviews);
  } catch (error) {
    next(error);
  }
};

 

 

 

✏️결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90