Node(Express) + Swagger 세팅

Marguerite·2024년 8월 8일
0

안녕하세요!
회사를 다니며 블로그 글을 작성하는 게 쉽지 않아서 마지막 글을 올린지 벌써 3년이... 지나버렸네요. 😅 (핑계대지마...)
지금부터라도 그동안 개인 노션에만 작성해왔던 글들을 차근차근 벨로그에 옮기면서 기술 블로그를 채워보려고 합니다. 〰️

Swagger

이번 글은 Node.js (Express) 프로젝트에 Swagger를 세팅하는 방법에 대해서 작성하도록 하겠습니다.

Swagger를 많이 들어보기는 했지만 회사가 아무래도 정신없이 프로젝트가 진행되다보니 정말 중요한 API 문서화를 하지 않아서 아직까지도 사용을 못해봤었는데 최근에 소규모의 프로젝트를 진행하게 되면서 Swagger를 접하게 되었습니다. 🙌🏻 (드디어!!) 그래서 따로 Swagger에 대해서 공부하고서 적용하는 것이 좋을 것 같아서 작성하게 되었습니다.


1️⃣   프로젝트 초기세팅

1-1. 프로젝트 초기화

우선 swagger_project 라는 폴더 생성 후 npm init 로 Node.js 프로젝트를 초기화하고 프로젝트의 package.json 파일을 생성합니다.

mkdir swagger_project
cd swagger_project
npm init -y

위의 명령어가 정상적으로 실행되면 아래와 같이 생성된 package.json 파일의 내용이 나옵니다. 설정한 프로젝트 이름에 따라 다를 수 있습니다.

1-2. 필요한 패키지 설치

Swagger 문서화하는 방법은 크게 3가지 방법(Annotation / JSON / YAML)이 있는데, 그중 YAML 파일을 사용하여 작성하기 위해 yamljs 패키지를 설치합니다.

npm install express swagger-ui-express yamljs

2️⃣   Express 서버 설정

2-1. 기본 서버 설정 (index.js)

패키지 설치까지 완료되었으면 이제 프로젝트 루트 디렉토리에 index.js 파일을 생성한 후, 아래와 같이 기본 Express 서버를 설정합니다. 아래 설정한 Express 서버는 3000 번 포트로 실행되며, / 경로로 GET 요청 시 "Express Server!" 를 반환합니다.

const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => {
  res.send("Express Server!");
});

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

3️⃣   Swagger 설정

이제 본격적으로 Swagger 설정을 해보도록 하겠습니다. 🧐
저는 YAML 파일 하나에 모든 API 를 설정하는 방법이 아닌 서비스별로 YAML 파일을 따로 가져가는 방법으로 작성하도록 하겠습니다.

3-1. 프로젝트 구조 설정

우선 서비스별로 가져가기 위해 폴더 및 파일을 생성해보도록 하겠습니다.
User 라는 서비스, Product 라는 서비스가 있다고 가정하여 생성하였으며, 원하는 서비스명으로 변경하셔도 괜찮습니다.


3-2. 서비스별 YAML 파일 작성

폴더 및 파일을 생성하여 프로젝트 구조를 위와 같이 설정하였으면 이제 서비스별 YAML 파일을 작성해보겠습니다.
아래 코드는 user.yaml 파일입니다. (product.yaml 도 비슷한 형식으로 product에 맞게 바꿔주면 됩니다.)

get:
  summary: 사용자 조회
  responses:
    "200":
      description: 사용자 목록을 조회하는 API
      content:
        application/json:
          schema:
            type: array
            items:
              $ref: "#/components/schemas/User"
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string

3-3. 공통 swagger.yaml 파일 작성

위에서 서비스별 YAML 파일을 작성하였으면 이제는 각 서비스의 YAML 파일을 통합하여 공통 문서를 작성하기 위한 공통 swagger.xml을 만들 차례입니다. 아래와 같이 swagger.xml을 생성합니다.

openapi: 3.0.0
info:
  title: Swagger - API Document
  description: Swagger를 사용한 API Document
  version: 1.0.0
paths:
  /users:
    $ref: "./routes/user/user.yaml"
  /products:
    $ref: "./routes/product/product.yaml"
components:
  schemas:
    User:
      $ref: "./routes/user/user.yaml#/components/schemas/User"
    Product:
      $ref: "./routes/product/product.yaml#/components/schemas/Product"
  • info : 문서의 기본 정보

    • title : API 문서의 제목
    • description : API 문서에 대한 설명
    • version : API 문서의 버전
  • paths : API 엔드포인트 정의 (HTTP 메서드 관련 정보 포함)

    • $ref : 서비스별 YAML 파일에서 정의된 paths 정보 참조
  • components : API 문서에서 재사용되는 구성 요소

    • schemas : 데이터 모델 (API에서 사용하는 데이터 구조)
    • $ref : 서비스별 YAML 파일에서 정의된 스키마 참조

3-4. Swagger 문서 파일 통합

이제 작성된 Swagger 문서 파일을 통합해보도록 하겠습니다. 어떤 방법으로 통합할지 검색해봤는데 index.js 파일에서 직접 YAML 파일을 읽어서 합치는 방법이 나오던데, 당장은 단순 예시이기 때문에 서비스가 2개만 있다고 하지만 추후에는 얼마나 서비스가 늘어날지 모르는 상황에서 좋지 않은 방법인 것 같아서 Swagger의 문서 자동 통합 도구를 사용하는 방법으로 진행해보겠습니다!

1) swagger-cli 패키지 설치

npm install -g swagger-cli

2) Swagger YAML 파일 통합

swagger-cli 명령어를 통해 Swagger YAML 파일을 통합합니다. (간단하죠?)

swagger-cli bundle swagger.yaml --outfile combined_swagger.yaml --type yaml
  • swagger.yaml(공통 파일명)과 관련된 모든 참조를 해결하여 combined_swagger.yaml(생성될 통합 파일명) 파일을 생성합니다.

3) Express 라우팅 설정 및 통합된 파일 적용

2번에서 swagger-cli 명령어를 통해 만들어진 combined_swagger.yaml 파일을 가지고 Express에 적용하고, 어떤 URI로 요청했을 경우 Swagger API 문서를 볼 것인지에 대해 라우팅 설정합니다.
index.js 에 Swagger UI를 추가한 후 api-docs 라는 URI 요청 시 Swagger UI를 통해 API 문서를 볼 수 있도록 설정합니다.

const express = require("express");
const swaggerUI = require("swagger-ui-express");
const YAML = require("yamljs");
const path = require("path");

const app = express();
const port = 3000;

// swagger 연결
const swagger = YAML.load(path.join(__dirname, "./combined_swagger.yaml"));
app.use("/api-docs", swaggerUI.serve, swaggerUI.setup(swagger));

app.get("/", (req, res) => {
  res.send("Hello World!");
});

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

Swagger를 세팅하다가 문득 왜 get이 아닌 use일까? 라는 생각이 들어서 찾아보게 되어서 정리하는 겸 혹시나 저처럼 궁금해하시는 분들에게 도움이 되셨으면 하는 바람으로 남겨놓겠습니다. 🙇🏻‍♀️

app.use() 를 사용하는 이유는?

  • app.use() 란?
    • Express에서 미들웨어를 설정하는 데 사용되는 함수이다.
    • 지정된 경로에 도달하는 모든 요청 (GET, POST, PUT, DELETE) 처리 가능하다.
    • 요청 URL을 지정하지 않아도 사용할 수 있으며 해당 경우에는 URL에 상관없이 매번 실행된다.

✅ Swagger 는 단순히 정적인 파일을 제공하는 것이 아닌 API 문서화와 관련된 다양한 기능을 제공하는 미들웨어이며, GET POST PUT DELETE 등 모든 HTTP 메서드에 작동하기 때문에 app.use()를 사용합니다.

위와 같이 설정한 후 node index.js 명령어를 터미널에 실행하면 http://localhost:3000/api-docs 에 접속하여 Swagger UI를 통해 API 문서를 볼 수 있습니다.


지금까지 Node(Express) 프로젝트에 Swagger 세팅하는 방법에 대해서 알아봤습니다. 확실히 많이 쓰는 데에는 이유가 있다고 생각하고 이제야 알게 되어 조금 늦은 것 같지만 이번 포스팅을 통해 알게 되었으니 실무에 적용을 해봐야겠다는 생각을 했습니다. 다만 제가 사용한 서비스별로 YAML을 통합하는 방법의 아쉬운 점은 "서비스의 yaml을 바꿀 때마다 swagger-cli 명령어를 입력해야된다는 점" 이었고, 어떤 식으로 개선할 수 있을지에 대해서도 시간이 된다면 포스팅할 예정입니다. 긴 글 읽어주셔서 감사합니다. 😊

profile
Developer 🐯

0개의 댓글