✨ 로그인 적용
로그인기능이 머지되기 전이라서 임의로 is_admin과 province_id를 코드에 적어놓고 테스트를 했었는데
미들웨어가 완성돼서 적용시켰다.
// hospitalRouter.js
const { authMiddleware } = require("../middlewares/auth");
...
router.get("", authMiddleware, errorHandler(hospitalController.getHospitalDataController));
router.get("/download", authMiddleware, errorHandler(hospitalController.downloadHospitalDataController));
authMiddleware에는 요청 headers의 Authorization키로 들어온 토큰을 빼서 나온 유저의 정보를 req.user에 저장하는 코드가 있다.
그걸 라우터에서 컨트롤러 전단계에 넣어주면 마치 파이썬 로그인 데코레이터처럼 컨트롤러로 가기 전에 authMiddleware에 들러서 토큰을 분석해서 인가처리를 할 수 있게 된다.
const getHospitalDataController = async (req, res) => {
// //====페이로드예시===========
// const payLoad = {
// id: 1,
// is_admin: 1,
// province_id: null,
// }
// //=======================
// const {is_admin, province_id} = payLoad;
const {userId, isAdmin, provinceId } = req.user;
그래서 임의로 사용하던 코드(주석처리된부분)를 지우고 미들웨어를 적용해서 코드를 수정했다.
✨ Swagger 적용
이번 과제에는 API문서를 swagger를 이용해서 작성해야 한다는 조건이 있었다.
세팅
// swagger/swagger.js
const swaggerUi = require("swagger-ui-express");
const swaggereJsdoc = require("swagger-jsdoc");
const options = {
swaggerDefinition: {
openapi: "3.0.n",
info: {
version: "1.0.0",
title: "Haii",
description: "Admin용 데이터 관리 프로그램 만들기",
},
servers: [
{
url: "http://localhost:8000",
},
],
components: {
securitySchemes: {
Authorization: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
value: "bearer <JWT token here>",
},
},
},
},
apis: ["./swagger/*/*.js"], // swagger폴더안에 기능에 따라 폴더를 나눠놓고 그 안에 작성할 모든 파일들을 api문서로 이용
};
const specs = swaggereJsdoc(options);
module.exports = {
swaggerUi,
specs,
};
// app.js
const createApp = () => {
...
const { swaggerUi, specs } = require("./swagger/swagger");
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(specs));
return app;
};
세팅을 한 후엔..노가다
요청 url, 바디에 들어갈 데이터 등 요청방식과 응답방식을 모두 직접 적어줘야 한다.
// swagger/hospital/hospitalList.js
/**
* @swagger
*
* /hospital:
* get:
* //요청에대한정보
*
* responses:
* //응답정보
* 400:
* //400응답의 정보
* 200:
* //200응답의 정보
*
*/
이런 형식으로 적어주면 된다.
요청 파라미터 정의
📍헤더의 토큰
원래 다른 코드를 찾아보다가
...
* /hospital:
* get:
* security:
* - Authorization: []
...
위와 같은 코드를 발견하고 이게 headers의 Authorization키에 담긴 토큰 확인하는 방법인줄 알고 복사해서 썼는데
이건 내가 만든 API에 요청할때 토큰이 필요하다는게 아니고
해당 API문서를 확인하려면 Authorization이 필요하다는 뜻이다.
이렇게 작성하고 명세서를 확인하면 제목에 열려있는 자물쇠 아이콘이 뜬다(인가가 필요하다곤 했는데 [ ]빈칸으로 둬서 열린 자물쇠로 나오고 누르면 열리는것같다.)
원래 목적인 header-Authorization키에 담긴 토큰을 확인하는건 아래 코드
...
* /hospital:
* get:
* summary: "치매센터 리스트 검색 & 조회 기능"
* parameters:
* - in: header // 어디에 담겨오는지: 헤더
* name: Authorization // 키: Authorization
* description: "인가에 필요한 토큰"
* required: true // 필수
* schema:
* type: string // 데이터타입
...
📍 쿼리파라미터
조건검색을 위한 쿼리 파라미터도 문서를 보고 아래처럼 작성했다.
...
* - in: query
* name: name
* schema:
* type: string
* description: 치매센터명 검색(단어 부분검색)
* - in: query
* name: representative
* schema:
* type: string
* description: 운영기관대표자명 검색(단어 부분검색)
...
나는 get메서드 요청 기능만 맡아서 요청 바디를 기술해줄 필요는 없었는데
바디에 대한 설명은 아래처럼 적어주면 된다.
...
* /users:
* post:
...
* requestBody:
...
응답
📍 http 상태코드가 같은데 다른 응답일때
...
*
* 200:
* description: 정상 요청일 경우 치매센터 리스트 엑셀파일 다운로드
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: number
* example: 200
* message:
* type: string
* example: "success"
*
* 400:
* description: 관리자에게 담당지역이 있을때
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* example: "admin cannot have province_id"
* 400:
* description: 관리자가 아닌데 담당지역이 없을때
* content:
* ...
응답도 이렇게 적어주면 되는데
위처럼 400이라는 응답이 두개면 에러가 난다.
(근데 이제보니까 403응답을 줬어야 했던것같다 권한이 없는거니까! 고치고싶은데 제출한 다음이라 못건드리겠다.....)
그래서 검색을 해서 스택오버플로우에서 방법을 찾았다.
schema에 oneOf옵션을 주는것!
* responses:
* 400:
* description: 관리자에게 담당지역이 있을때 / 관리자가 아닌데 담당지역이 없을때
* content:
* application/json:
* schema:
* oneOf:
* - $ref: '#/components/schemas/adminwprovince'
* - $ref: '#/components/schemas/noadminwoprovince'
* examples:
* adminwprovince:
* summary: 관리자에게 담당지역이 있을때
* value:
* status: 400
* message: "admin cannot have province_id"
* noadminwoprovince:
* summary: 관리자가 아닌데 담당지역이 없을때
* value:
* status: 400
* message: "province_id not provided"
*
...
*
* components:
* schemas:
* adminwprovince:
* type: object
* properties:
* status:
* type: number
* example: 400
* message:
* type: string
* example: "admin cannot have province_id"
* noadminwoprovince:
* type: object
* properties:
* status:
* type: number
* example: 400
* message:
* type: string
* example: "province_id not provided"
*
*/
이렇게 만들고 명세서를 열면

이렇게 예시 하나만 나오고 옆에 "Schema" 를 누르면

이렇게 모든 예시를 확인할 수 있다.
나머지 참고했던 링크
https://github.com/belgif/rest-guide/issues/79
https://swagger.io/docs/specification/data-models/data-types/
'wecode' 카테고리의 다른 글
| 프리온보딩 | 2차과제 - 2: 엑셀다운로드, 검색기능 (0) | 2022.10.09 |
|---|---|
| 프리온보딩 | 2차과제 - 1: db모델링, 데이터조회기능 (0) | 2022.10.09 |
| 프리온보딩 | 1차과제 - 3 (1) | 2022.10.06 |
| 프리온보딩 | 1차과제 - 2 (0) | 2022.10.06 |
| 프리온보딩 | 1차과제 - 1 (0) | 2022.10.05 |