ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • node.js ts 프로젝트에 swagger를 적용해보자!
    개발연습/swagger 2021. 9. 17. 12:23

    프로젝트를 진행할 때 api문서는 필수적이다.

    한명이 프론트-백을 전부 담당하면 모르겠지만, 일반적으로는 다른 인원이 다루기에

    각 라우터에 대한 정확한 input/output 값을 알고 있어야 한다.

    게다가 우리 프로젝트는 ts를 적용중으로 더욱 중요하다!

     

    원래는 마크다운으로 관리를 하고 있었지만... 슬슬 귀찮아지는게 느껴져서 api문서 툴을 알아보게 되었다.

    api문서를 다루는 툴은 여러가지가 있지만

    그중에서도 swagger에 대한 추천이 많아서 적용하게 되었다.

     

    그런데.. swagger를 적용하는 방법도 여러가지가 있고 해서 열심히 영어읽느라 고생 좀 했다.

     

     

    인터넷을 통해 알아본 방법으로 swagger를 적용하는 방법은 크게 두가지가 있다는 것을 알았다.

     

    1. 각 ts파일에 주석형식으로 추가하는 방법

    2. json 또는 yaml파일을 이용해 따로 관리하는 방법.

     

    아무래도 서버코드들이 담겨있는 파일에 주석을 추가하게 되면 더럽기도 하고 불편하기도 할 듯 하여 두번째 방법을 적용하기로 선택하였다.

    그 중에서도 { } 를 열고 닫는게 귀찮아서 yaml파일을 이용하는 것을 선택하였다.

     

    해당 방법에 필요한 패키지는 다음과 같다. 

    npm i swagger-cli swagger-ui-express yamljs @types/yamljs @types/swagger-ui-express

    본인의 프로젝트의 성격에 따라서 적절히 dev옵션을 붙여서 install하자.

     

    다음으로는 디렉토리 구조를 짜야하는데..

    당연히!! 하나의 yaml파일에 모든 api를 때려박으면 겁나게 길고 나중에 수정하기 힘들다.

    따라서 나는 라우터 파일 기준으로 yaml파일을 생성했다.

    auth, user, video는 각 ts파일에 포함된 라우터에 대한 정보를 yaml파일에 기록했다고 보면 된다.

    openapi.yaml이 하는 일은

    1. 3개의 yaml파일로 흩어져 있는 라우터 정보들을 모아주는 역할

    2. 중복되는 component들을 관리하는 역할(거의 동일한 200 response라던가, db schema라던가)

     

    openapi.yaml파일이 존재함으로써 항상 반복되는 문장을 쓸 필요 없이 링크를 걸면 된다.

     

    마지막으로 swagger폴더의 상위디렉토리에 swagger.yaml파일을 배치했다.(app.ts와 같은 레벨)

     

    다시 설명하면, auth, user, video yaml은 이름이 같은 ts파일의 라우터 정보를 가지고 있고,

    openapi.yaml파일은 중복되는 component들의 정보를 포함하면서, 각 라우터에 대한 정보를 auth, user, video yaml에서 불러올 수 있도록 링크를 걸어놓는다.

    그럼 swagger.yaml은 이 모든 링크되어있는 부분들을 원래 코드로 대체해서 하나의 큰 파일이 되는 것이다.

    (자세한 내용은 아래에 코드를 보며 추가설명을 하겠다.)

     

     

    그러면 본격적으로 swagger 세팅을 시작하자.

     

    우선 스크립트를 추가해준다.

    "api-docs": "swagger-cli bundle ./src/swagger/openapi.yaml --outfile src/swagger.yaml --type yaml",
    "predev": "npm run api-docs"

    swagger-cli가 openapi.yaml을 읽어서 모든 링크들을 불러와서 하나의 파일로 만들어서 swagger.yaml로 출력을 한다.

    그리고 매번 npm run api-docs 하기 귀찮으니 predev에 걸어버려서, npm run dev시마다 자동으로 swagger.yaml파일이 최신화되도록 한다.

     

    그리고 app.ts에 swagger 정보를 넣어준다.

    import swaggerUi from 'swagger-ui-express';
    import YAML from 'yamljs';
    import path from 'path';
    
    ...
    
    const swaggerSpec: any = YAML.load(path.join(__dirname, './swagger.yaml'));
    app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));

    swagger-ui-express는 작성한 yaml파일을 웹으로 예쁘게 보여주는 역할이라고 한다.

    ts를 쓰는 입장에서 any타입을 사용하면 안되는데.. 아무리 구글링을 해도 해결방법을 모르겠다.

    app.use를 통해 /api-docs 에 스웨거를 연결했으므로, 서버url/api-docs로 접근하면 api문서를 확인 할 수 있게 된다.

     

     

    이제 메인이 되는 openapi.yaml파일에 뼈대가 되는 코드를 작성한다

    openapi: '3.0.0'
    info:
      version: 0.4.0
      title: eedited API docs
      description: eedited의 API 문서입니다
      license:
        name: MIT
    servers:
      - url: http://localhost:3000/
    paths:
    components:

     

    이 상태에서 npm run dev를 하면, swagger.yaml파일에 똑같은 내용이 작성되면서 서버가 실행되는것을 확인 할 수 있다.

     

    잘 작성되었으면 localhost:3000/api-docs에 접속 시 다음과 같은 화면이 나타난다.

     

     

    이제 components 부분을 채워보자.

    문법적인 부분은 swagger의 공식문서에 잘 나와있으므로 생략하겠다.

    다음은 예시로 200 responses항목을 작성한 모습이다.

    components:
      responses:
        successResponse:
          description: successful request
          content:
            application/json:
              schema:
                type: object
                properties:

    우리 프로젝트의 경우에는 항상 json을 return하기로 합의했다. 따라서 마지막 schema의 type이 object이다.

    그럼 이 successResponse를 재활용해보자.

     

    다음은 auth.ts의 logout 라우터에 대한 기술이다.

    auth.yaml파일을 만들고, 다음처럼 작성한다.

    /auth/logout:
      get:
        tags:
          - /auth
        summary: logout router
        responses:
          '200':
            $ref: './openapi.yaml#/components/responses/successResponse'

    ref 문법의 경우 공식문서에 나와있으니 자세히 설명하지 않겠다.

    위 successResponse를 전부 다시 작성하는 것이 아닌, 링크를 걸어서 가져오는 형식이므로 코드가 짧아지게 된다.

     

    그러면, 이젠 auth.yaml파일에 작성된 /auth/logout 을 openapi.yaml에서 ref로 가져와야 한다.

    paths:
      /auth/signup: 
        $ref: './auth.yaml#/~1auth~1signup'
      /auth/signup/email:
        $ref: './auth.yaml#/~1auth~1signup~1email'
      /auth/check:
        $ref: './auth.yaml#/~1auth~1check'
      /auth/login:
        $ref: './auth.yaml#/~1auth~1login'
      /auth/logout:
        $ref: './auth.yaml#/~1auth~1logout'

    이런 식으로, 다른 yaml파일에 작성한 내용을 ref를 통해 불러올 수 있다. 저 괴상하게 중복되는 ~1같은 것들도 다 공식문서에 나와있으니 설명은 생략하겠다.

     

     

    이제 npm run api-docs를 하면 swagger.yaml파일에는 다음처럼 작성이 된다.

    openapi: 3.0.0
    info:
      version: 0.4.0
      title: eedited API docs
      description: eedited의 API 문서입니다
      license:
        name: MIT
    servers:
      - url: 'http://localhost:3000/'
    paths:
      /auth/signup:
        post:
          tags:
            - /auth
          summary: SignUp
          requestBody:
            description: need user's personal info
            required: true
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    userId:
                      type: string
                    password:
                      type: string
                    email:
                      type: string
                      format: email
                    birthday:
                      type: string
                      format: date
                    nickname:
                      type: string
                    profilePicture:
                      type: string
                      format: uri
          responses:
            '200':
              $ref: '#/components/responses/successResponse'
            '500':
              allOf:
                - $ref: '#/components/responses/routerErrorResponse'
                - content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          info:
                            type: string
                            example: '/auth/signup - DB Error : Checks DB Connection or CRUD'
                            
     ...

    이런식으로 ref부분이 다 불러와져서 하나의 yaml파일로 통합이 되는 것이다.

     

     

    그럼 이제 npm run dev로 실행을 하고 localhost:3000/api-docs에 접속을 하면???

     

    와! 깔끔하게 정리된 모습이다. (RESTful api가 적용되다 말았다 하는 것은 눈감아주자)

     

    yaml파일 문법에 대한 내용은 공식문서에 잘 나와있지만, 그 외의 필요한 패키지, app.ts에서 연결하는 방법, 모듈화를 위해 필요한 스크립트와 ref의 상세한 사용법들 그리고 openapi.yaml파일의 기본뼈대(저 항목들 중 하나라도 빠지니 랜더링이 되지 않더라..)는 나와있지 않아서 꽤나 고생 좀 했다. 

     

    그런데.. 노가다를 뛰고 나니까 postman에서 관리하는 것과 차이가 무엇인지 모르겠다. 억지로 찾자면... 각 라우터에 대한 output값의 대략적인 정보를 미리 알 수 있는것과 해당 페이지에서 바로 테스트가 가능하다는것??

    댓글

Designed by Tistory.