코딩기록

항해 87일) nodejs swagger(json). API 문서관리 본문

항해99/챕터6 실전 프로젝트

항해 87일) nodejs swagger(json). API 문서관리

뽀짝코딩 2022. 4. 6. 20:45
728x90

swagger에 한,, 하루 반 소요된거 같다. 스웨거만 붙든건 아니었지만 

url설정에 문제가 있었지만 해결되었고 yaml방식은 직접 .yaml파일에 적어야하지만 json은 자동으로 생성되고 몇가지만 수정하는 방식이여서 json으로 했다. yaml도 자동으로 틀을 만들어줄거 같은데 아직 못찾았다.

swagger도 2.0버전과 3.0.0버전이 있는데 나는 2.0버전이다.

 

1. 모듈 설치

$ npm install swagger-ui-express
$ npm install swagger-autogen

 

 

2. 파일구조

여기서 app.js, swagger.js, swagger-output.json, models>index.js, .env 파일이 사용된다.

 

 

 

 app.js 

//상단에 위치

//스웨거 자동생성을 위한 코드
const swaggerUi = require("swagger-ui-express");
// //스웨거 아웃풋파일 저장 위치
const swaggerFile = require("./swagger-output.json");


//하단에 위치
// path설정 /swagger 
app.use("/swagger", swaggerUi.serve, swaggerUi.setup(swaggerFile));

 

 swagger.js 

const swaggerAutogen = require("swagger-autogen")();

const doc = {
    info: {
        title: "omogjomog",
        description: "omogjomog API",
    },
    //로컬 테스트
    // host: "localhost:3000",
    //ec2 인스턴스 주소
    host: "13.125.238.144",
    schemes: ["http"],
};

const outputFile = "./swagger-output.json";
const endpointsFiles = ["./app.js"];

swaggerAutogen(outputFile, endpointsFiles, doc);

//swaggerAutogen으로 outputfile 파일을 app.js 루트로 api 들을 생성한다.
//이때 명령어는 터미널에서 node swagger.js
//명령어까지 입력하면 swagger-output.json파일이 생성된다.
//package.json에 "prestart": "node ./swagger.js" 설정하면 명령어는 npm start

명령어까지 입력하면 swagger-output.json파일이 생성된다.

 

 

 

보통app.js안에

const port = 3000;

이라고 포트를 쓰지만 나는 dotenv에 비번등 중요한걸 숨겨놨다. 그래서 로컬에서 테스트 할때 models>index.js는

아래와 같이 쓴다.

 

 models > index.js 

const mongoose = require('mongoose');

const connect = () => {
  mongoose
    .connect('mongodb://localhost:27017/Omok', {
      ignoreUndefined: true,
    })
    .catch((error) => {
      console.error(error);
    });
};

module.exports = connect;

 .env 

PORT=3000
MONGO_URL='mongodb://test:test@localhost:27017/Omok'
Algorithm='sha512'
TOKENKEY='my-secret-key'
DSN='https://f4d277bb0bba4288b76e4171b4cbcc54@o1188771.ingest.sentry.io/6308910'

여기까지 작성하고 vscode터이널에서 node ./swagger.js 명령어를 치면  swagger-output.json 파일이 생성된다.

이파일은 프로젝트의 코드를 기초로 틀만 생성되는건데 이안에 추가로 내 프로젝트에 맞게 설명을 적으면된다.

"tags": ["user"] 는 api 문서를 보기 편하게  분류 해준다.

"summary": "회원가입" 은 API문서에서 볼수있는 짧은 설명이다.

properties안에 id, pass등 reqest가 있고 example에 실제로 브라우저에서 고객이 입력하는 형식을 적는다.

"example": "user1" 처럼 쓰면 된다.

 

 

 

 swagger-output.json 

더보기

 

{
  "swagger": "2.0",
  "info": {
    "title": "omogjomog",
    "description": "omogjomog API",
    "version": "1.0.0"
  },
  "host": "13.125.229.125",
  "contact": { 
    "git": "https://github.com/Omok-BE/Omok-BE" 
  },
  "basePath": "/",
  "schemes": [
    "https"
  ],
  "paths": {
    "/signup": {
      "post": {
        "tags": ["user"],
        "description": "회원가입",
        "summary": "회원가입",
        "parameters": [
          {
            "name": "users",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "example": "user1"
                },
                "email": {
                  "example": "user1@naver.com"
                },
                "pass": {
                  "example": "user1"
                },
                "confirmPass": {
                  "example": "user1"
                },
                "profileImage": {
                  "example": ".svg"
                }
              }
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/login": {
      "post": {
        "tags": ["user"],
        "description": "로그인",
        "summary": "로그인",
        "parameters": [
          {
            "name": "login",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "example": "user1"
                },
                "pass": {
                  "example": "user1"
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/findpass": {
      "post": {
        "tags": ["user"],
        "description": "비밀번호 찾기 [유저 확인]",
        "summary": "비밀번호 찾기[유저 확인]",
        "parameters": [
          {
            "name": "find",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "example": "user1"
                },
                "email": {
                  "example": "user1@naver.com"
                }
              }
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/newpass": {
      "post": {
        "tags": ["user"],
        "description": "비밀번호 찾기 [새 비밀번호 입력]",
        "summary": "비밀번호 찾기 [새 비밀번호 입력]",
        "parameters": [
          {
            "name": "newpass",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "example": "user1"
                },
                "email": {
                  "example": "user1@naver.com"
                },
                "newPass": {
                  "example": "any"
                }
              }
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/userinfo/{id}": {
      "get": {
        "tags": ["user"],
        "description": "로그인 체크",
        "summary": "로그인 체크",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/lobby": {
      "get": {
        "tags": ["lobby"],
        "description": "로비첫 화면",
        "summary": "로비첫 화면",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/lobby/userList/{id}": {
      "get": {
        "tags": ["lobby"],
        "description": "로비에서 offline제외 유저리스트",
        "summary": "로비에서 offline제외 유저리스트",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/lobby/leaderList": {
      "get": {
        "tags": ["lobby"],
        "description": "로비에서 포인트기준 리더리스트",
        "summary": "로비에서 포인트기준 리더리스트",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/leaderBoard": {
      "get": {
        "tags": ["lobby"],
        "description": "리더보드: 로비 순위표",
        "summary": "리더보드: 로비 순위표",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/lobby/create": {
      "post": {
        "tags": ["lobby"],
        "description": "게임방 생성",
        "summary": "로비에서 게임방 생성",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "roomName": {
                  "example": "1"
                },
                "id": {
                  "example": "user1"
                },
                "timer": {
                  "example": "5 : 00"
                },
                "boardColor": {
                  "example": "1"
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/lobby/joinroom/{roomNum}": {
      "get": {
        "tags": ["lobby"],
        "description": "방 참가: 모달창뜰때",
        "summary": "방 참가: 모달창뜰때",
        "parameters": [
          {
            "name": "roomNum",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/lobby/joinroom": {
      "post": {
        "tags": ["lobby"],
        "description": "방 참가: 모달창 입력",
        "summary": "방 참가: 모달창 입력",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "roomNum": {
                  "example": "1"
                },
                "id": {
                  "example": "user1"
                },
                "state": {
                  "example": "inRoom"
                }
              }
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/lobby/fastPlayer/{id}": {
      "get": {
        "tags": ["lobby"],
        "description": "빠른 참가(플레이어)",
        "summary": "빠른 참가(플레이어)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/lobby/fastObserver/{id}": {
      "get": {
        "tags": ["lobby"],
        "description": "빠른 참가(관전자)",
        "summary": "빠른 참가(관전자)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/lobby/roomNumJoin": {
      "post": {
        "tags": ["lobby"],
        "description": "방번호 참가",
        "summary": "방번호 참가",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "example": "user1"
                },
                "roomNum": {
                  "example": "1"
                }
              }
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/lobby/logout": {
      "post": {
        "tags": ["lobby"],
        "description": "로그아웃",
        "summary": "로그아웃",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "example": "any"
                }
              }
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/game/create": {
      "post": {
        "tags": ["game"],
        "description": "대기실 => 게임방 입장시 게임방 생성",
        "summary": "대기실 => 게임방 입장시 게임방 생성",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "roomNum": {
                  "example": "1"
                },
                "blackTeamPlayer": {
                  "example": "user1"
                },
                "blackTeamObserver": {
                  "example": "user2"
                },
                "whiteTeamPlayer": {
                  "example": "user3"
                },
                "whiteTeamObserver": {
                  "example": "user4"
                }
              }
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/game/start/{gameNum}": {
      "get": {
        "tags": ["game"],
        "description": "게임방 입장해서 정보가져오기",
        "summary": "게임방 입장해서 정보가져오기",
        "parameters": [
          {
            "name": "gameNum",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/game/bugreport": {
      "post": {
        "tags": ["game"],
        "description": "[버그리폿]",
        "summary": "[버그리폿]",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "input": {
                  "example": "text 설명"
                },
                "gameNum": {
                  "example": "1"
                },
                "gameInfo": {
                  "example": "[{ 'gameNum': 1, 'gameName':'게임ㄱㄱ', 'blackTeamPlayer': 'user1', 'blackTeamObserver': 'user2', 'whiteTeamPlayer': 'user3', 'whiteTeamObserver': 'user4', 'timer': '3 : 00' }]"
                },
                "userInfo": {
                  "example": "{ 'id': 'user1', 'state': 'whitePlayer', 'score': {'win':1, 'lose':0}, 'point': 1000, 'profileImage': ' .svg' }"
                }
              }
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/gameFinish": {
      "post": {
        "tags": ["game"],
        "description": "[결과창]:게임이 끝나면 바로 보내는 내용",
        "summary": "[결과창]:게임이 끝나면 바로 보내는 내용",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "userInfo": {
                  "example": "{ 'id': 'user1', 'state': 'whitePlayer', 'score': {'win':1, 'lose':0}, 'point': 1000, 'profileImage': ' .svg' }"
                },
                "gameNum": {
                  "example": "1"
                },
                "result": {
                  "example": "{'win': 'user1', 'state': 'whitePlayer'}"
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/gameFinish/show": {
      "post": {
        "tags": ["game"],
        "description": "[결과창]:페이지로 들어가자마자",
        "summary": "[결과창]:페이지로 들어가자마자",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "example": "user1"
                },
                "gameNum": {
                  "example": "1"
                },
                "result": {
                  "example": "{ 'win': 'user1', 'state': 'whitePlayer' }"
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/game/delete/{gameNum}": {
      "delete": {
        "tags": ["game"],
        "description": "방에서 나가기",
        "summary": "방에서 나가기",
        "parameters": [
          {
            "name": "gameNum",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/admin/login": {
      "post": {
        "tags": ["admin"],
        "description": "관리자 로그인",
        "summary": "관리자 로그인",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "example": "admin"
                },
                "pass": {
                  "example": "pass"
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/admin/waitingRoom/list": {
      "get": {
        "tags": ["admin"],
        "description": "대기방 리스트 불러오기",
        "summary": "대기방 리스트 불러오기",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/admin/waitingRoom/delete/{roomNum}": {
      "delete": {
        "tags": ["admin"],
        "description": "대기방 삭제",
        "summary": "대기방 삭제",
        "parameters": [
          {
            "name": "roomNum",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/admin/gameRoom/list": {
      "get": {
        "tags": ["admin"],
        "description": "게임방 리스트 불러오기",
        "summary": "게임방 리스트 불러오기",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/admin/gameRoom/delete/{gameNum}": {
      "delete": {
        "tags": ["admin"],
        "description": "게임방 삭제",
        "summary": "게임방 삭제",
        "parameters": [
          {
            "name": "gameNum",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/admin/users/list": {
      "get": {
        "tags": ["admin"],
        "description": "유저 리스트 불러오기",
        "summary": "유저 리스트 불러오기",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/admin/users/editPoint/{id}": {
      "put": {
        "tags": ["admin"],
        "description": "유저 포인트 수정하기",
        "summary": "유저 포인트 수정하기",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "body",
            "in": "body",
            "schema": {
              "type": "object",
              "properties": {
                "point": {
                  "example": 1000
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    },
    "/admin/users/delete/{id}": {
      "delete": {
        "tags": ["admin"],
        "description": "유저 삭제하기",
        "summary": "유저 삭제하기",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          }
        }
      }
    }
  }
}

 

여기까지 하고 vscode 터미널에 node server.js 명령어를 적으면 서버가 돌아간다

그럼 브라우저에 주소를 입력하면 아래와 같은 화면이 뜬다.(ec2 인스턴스 주소)

로컬 주소- localhost:3000/swagger 

ec2 인스턴스 주소- http://13.125.229.25/swagger

 

API문서 테스트 이미지

1. 오른쪽 상단 Try it out 클릭

 

2. Object { body } 안 내용 작성 

내가 적은 swagger-output.json 내용이 그대로 나와서 필요한 부분만 수정하면된다.

파랑색   Execute   버튼을 누른다.

 

3. 성공하면 아래 201이 뜨고

 

실패하면 아래와 같이 오류 메시지가 뜬다.  회원가입 API 테스트를 했고 2가지 실패 상황이 발생했다.

 

1-1. 400 에러 (설정한 에러) 

비밀번호 2번 입력하는데 비밀번호 확인에서 다른 비밀번호를 입력했다.

1-2. 400 에러 (설정한 에러)

 

2. cors 에러가 났고 app.js에서 cors관련해서 확인하면 된다.

 

 

 

 

 

 

 

 

 

 

반응형
Comments