Swagger

Swagger는 RESTful API를 설계, 개발, 문서화, 테스트하기 위한 종합적인 도구 모음이다.
2010년 Tony Tam이 Wordnik(온라인 사전 서비스)의 API를 문서화하기 위해 최초로 개발한 이 도구는 오늘날 API 개발 생태계에서 필수적인 요소로 자리 잡았다.

Swagger는 단순한 문서화 도구가 아닌, API 개발 전체 수명주기를 지원하는 통합 플랫폼이다.
개발자들은 Swagger를 통해 API를 쉽게 이해하고, 직접 테스트하며, 클라이언트 SDK를 자동으로 생성할 수 있다. 이러한 특성으로 인해 Swagger는 API 중심 개발 방법론의 핵심 도구로 사용되고 있다.

Swagger와 OpenAPI의 관계

Swagger와 OpenAPI의 관계는 많은 개발자들이 혼동하는 부분이다.
이 둘의 관계를 명확히 이해하는 것이 중요하다:

역사적 발전

초기에 Swagger는 API를 설명하기 위한 명세(Specification)와 이를 지원하는 도구 모음 모두를 가리켰다. 그러나 2015년, Swagger 명세는 Linux Foundation 산하의 OpenAPI Initiative(OAI)에 기부되었고, 이때부터 명세 자체는 “OpenAPI 명세(OpenAPI Specification, OAS)“라는 새로운 이름을 갖게 되었다.

현재의 구분

현재의 구분은 다음과 같다:

다시 말해, OpenAPI는 API를 설명하는 공식 명세(언어)이고, Swagger는 이 명세를 활용하여 API를 설계, 구축, 문서화하는 도구 세트이다.

Swagger 도구 에코시스템

Swagger 에코시스템은 다양한 도구로 구성되어 있으며, 각각은 API 개발 수명주기의 특정 측면을 지원한다:

Swagger Editor

Swagger Editor는 개발자가 OpenAPI 명세를 작성하고 편집할 수 있는 브라우저 기반 에디터이다.
주요 특징은 다음과 같다:

Swagger Editor는 온라인에서 직접 사용하거나 로컬에 설치하여 사용할 수 있다.

Swagger UI

Swagger UI는 OpenAPI 명세를 시각적이고 대화형 문서로 변환하는 도구이다.
이 도구의 주요 특징은 다음과 같다:

많은 기업들이 자사의 API 개발자 포털에 Swagger UI를 통합하여 사용자 친화적인 문서를 제공하고 있다.

Swagger Codegen

Swagger Codegen은 OpenAPI 명세에서 클라이언트 SDK, 서버 스텁, 문서를 자동으로 생성하는 도구:

Swagger Codegen은 API 개발 시간을 크게 단축하고, 클라이언트-서버 간 일관성을 보장하는 데 도움이 된다.

Swagger Inspector

Swagger Inspector는 API를 빠르게 테스트하고 OpenAPI 정의를 자동으로 생성하는 도구:

이 도구는 특히 이미 존재하는 API의 문서화를 자동화하는 데 유용하다.

SwaggerHub

SwaggerHub는 팀을 위한 API 설계와 문서화를 위한 통합 플랫폼:

SwaggerHub는 SmartBear가 제공하는 상용 서비스로, 기업 환경에서 API 개발 워크플로우를 관리하기 위한 종합적인 솔루션이다.

Swagger의 실제 구현 및 사용 방법

OpenAPI 명세 작성하기

Swagger를 활용하기 위한 첫 번째 단계는 OpenAPI 명세를 작성하는 것이다.

이를 위한 두 가지 주요 접근법이 있다:

설계 우선 접근법(Design-First Approach)

이 접근법에서는 API 구현 전에 OpenAPI 명세를 먼저 작성한다:

  1. Swagger Editor를 사용하여 API 명세를 YAML 또는 JSON 형식으로 작성한다.
  2. 작성된 명세를 검토하고 필요에 따라 수정한다.
  3. Swagger Codegen을 사용하여 서버 스텁과 클라이언트 SDK를 생성한다.
  4. 생성된 코드를 기반으로 API를 구현한다.

다음은 간단한 OpenAPI 3.0 명세의 예:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
openapi: 3.0.0
info:
  title: 사용자 API
  description: 사용자 정보를 관리하는 API
  version: 1.0.0
servers:
  - url: https://api.example.com/v1
paths:
  /users:
    get:
      summary: 모든 사용자 조회
      responses:
        '200':
          description: 성공적인 응답
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
    post:
      summary: 새 사용자 생성
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NewUser'
      responses:
        '201':
          description: 사용자 생성 성공
  /users/{userId}:
    get:
      summary: 특정 사용자 조회
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: 성공적인 응답
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
        createdAt:
          type: string
          format: date-time
    NewUser:
      type: object
      required:
        - name
        - email
      properties:
        name:
          type: string
        email:
          type: string
코드 우선 접근법(Code-First Approach)

이 접근법에서는 기존 API 코드에 주석이나 어노테이션을 추가하여 OpenAPI 명세를 생성한다:

  1. API 코드를 구현한다.
  2. 코드에 Swagger/OpenAPI 관련 주석이나 어노테이션을 추가한다.
  3. 도구를 사용하여 코드에서 OpenAPI 명세를 생성한다.

다음은 주요 프레임워크별 구현 예시:

Spring Boot (Java)

Spring Boot에서는 springdoc-openapi 라이브러리를 사용하여 OpenAPI 3.0 명세를 생성할 수 있다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {

    @Operation(summary = "모든 사용자 조회")
    @ApiResponse(responseCode = "200", description = "성공적인 응답",
                 content = @Content(mediaType = "application/json",
                 schema = @Schema(implementation = User[].class)))
    @GetMapping
    public List<User> getAllUsers() {
        // 구현 코드
    }

    @Operation(summary = "특정 사용자 조회")
    @ApiResponse(responseCode = "200", description = "사용자를 찾음")
    @ApiResponse(responseCode = "404", description = "사용자를 찾을 수 없음")
    @GetMapping("/{userId}")
    public User getUserById(
        @Parameter(description = "조회할 사용자의 ID") @PathVariable Long userId
    ) {
        // 구현 코드
    }

    @Operation(summary = "새 사용자 생성")
    @ApiResponse(responseCode = "201", description = "사용자 생성 성공")
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public User createUser(@RequestBody User user) {
        // 구현 코드
    }
}

Spring Boot 애플리케이션에 springdoc-openapi 의존성을 추가하면, 자동으로 /v3/api-docs 엔드포인트에서 OpenAPI 문서를 제공하고, /swagger-ui.html에서 Swagger UI를 사용할 수 있다.

Express (Node.js)

Express에서는 swagger-jsdocswagger-ui-express 패키지를 사용하여 OpenAPI 명세를 생성하고 문서화할 수 있다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
const express = require('express');
const swaggerJsdoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');

const app = express();

// Swagger 정의
const options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: '사용자 API',
      version: '1.0.0',
      description: '사용자 정보를 관리하는 API',
    },
    servers: [
      {
        url: 'http://localhost:3000',
      },
    ],
  },
  apis: ['./routes/*.js'], // 라우트 파일 경로
};

const specs = swaggerJsdoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));

/**
 * @swagger
 * /users:
 *   get:
 *     summary: 모든 사용자 조회
 *     responses:
 *       200:
 *         description: 성공적인 응답
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items:
 *                 $ref: '#/components/schemas/User'
 */
app.get('/users', (req, res) => {
  // 구현 코드
});

/**
 * @swagger
 * /users/{userId}:
 *   get:
 *     summary: 특정 사용자 조회
 *     parameters:
 *       - in: path
 *         name: userId
 *         required: true
 *         schema:
 *           type: integer
 *     responses:
 *       200:
 *         description: 사용자를 찾음
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/User'
 *       404:
 *         description: 사용자를 찾을 수 없음
 */
app.get('/users/:userId', (req, res) => {
  // 구현 코드
});

/**
 * @swagger
 * components:
 *   schemas:
 *     User:
 *       type: object
 *       properties:
 *         id:
 *           type: integer
 *         name:
 *           type: string
 *         email:
 *           type: string
 */
FastAPI (Python)

FastAPI는 OpenAPI를 기본적으로 지원하므로 추가 설정 없이 자동으로 API 문서를 생성한다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from fastapi import FastAPI, HTTPException, Path
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime

app = FastAPI(
    title="사용자 API",
    description="사용자 정보를 관리하는 API",
    version="1.0.0"
)

class UserBase(BaseModel):
    name: str
    email: str

class UserCreate(UserBase):
    pass

class User(UserBase):
    id: int
    created_at: datetime
    
    class Config:
        orm_mode = True

@app.get("/users/", response_model=List[User], summary="모든 사용자 조회")
async def get_users():
    """
    모든 사용자의 목록을 반환합니다.
    """
    # 구현 코드

@app.get("/users/{user_id}", response_model=User, summary="특정 사용자 조회")
async def get_user(
    user_id: int = Path(..., description="조회할 사용자의 ID")
):
    """
    특정 ID를 가진 사용자의 정보를 반환합니다.
    
    - **user_id**: 조회할 사용자의 고유 ID
    """
    # 구현 코드
    # 사용자가 없으면 예외 발생
    # raise HTTPException(status_code=404, detail="User not found")

@app.post("/users/", response_model=User, status_code=201, summary="새 사용자 생성")
async def create_user(user: UserCreate):
    """
    새로운 사용자를 생성합니다.
    """
    # 구현 코드

FastAPI는 자동으로 /docs 경로에 Swagger UI를, /redoc 경로에 ReDoc 문서를 제공한다.

Swagger UI를 통한 API 테스트

Swagger UI를 사용하면 API를 쉽게 탐색하고 테스트할 수 있다.

일반적인 워크플로우는 다음과 같다:

  1. Swagger UI에 접속(일반적으로 /swagger-ui.html 또는 /docs 경로).
  2. API 엔드포인트 목록에서 테스트하려는 엔드포인트를 선택.
  3. “Try it out” 버튼을 클릭.
  4. 필요한 파라미터와 요청 본문을 입력.
  5. “Execute” 버튼을 클릭하여 API를 호출.
  6. 요청 URL, 헤더, 본문과 함께 응답 결과를 확인.

이 대화형 문서는 개발자가 API를 이해하고 테스트하는 데 매우 유용하다.

Swagger의 실제 적용 사례

기업 API 프로그램

많은 기업들이 Swagger를 API 개발 및 문서화의 핵심 도구로 사용하고 있다:

대기업 사례
금융 서비스 분야

금융 산업에서는 보안과 정확한 문서화가 중요하기 때문에 Swagger가 널리 사용된다:

내부 API 거버넌스

많은 조직에서는 내부 API 관리에도 Swagger를 활용한다:

Swagger의 장점

Swagger는 API 개발과 관리에 여러 가지 중요한 이점을 제공한다:

개발 효율성 향상

문서화 자동화

품질 향상

협업 개선

Swagger 사용 시 고려사항 및 한계

Swagger의 많은 장점에도 불구하고, 사용 시 고려해야 할 몇 가지 사항과 한계가 있다:

학습 곡선

OpenAPI 명세는 광범위하고 복잡하여 완전히 익히는 데 시간이 필요하다.
특히 대규모 API의 경우 명세 작성이 까다로울 수 있다.

유지보수 부담

코드 우선 접근법을 사용할 경우, 코드와 주석을 동기화된 상태로 유지하는 것이 중요하다. 잘못된 주석이나 누락된 업데이트는 잘못된 문서로 이어질 수 있다.

설계 제약

OpenAPI는 RESTful API에 최적화되어 있어, GraphQL, gRPC, WebSocket 등 다른 유형의 API를 문서화하는 데는 제한이 있다. (이러한 API 유형에는 각각 전용 문서화 도구가 있다.)

도구 의존성

Swagger 도구 생태계에 의존하면 향후 도구가 변경되거나 사용 중단될 경우 마이그레이션 문제가 발생할 수 있다.

Swagger 도입을 위한 모범 사례

조직에서 Swagger를 효과적으로 도입하기 위한 모범 사례는 다음과 같다:

명확한 목표 설정

적절한 접근법 선택

스타일 가이드 및 템플릿 개발

개발 워크플로우 통합

교육 및 지원


용어 정리

용어설명

참고 및 출처