개발 일지

API Documentation 정리 (oas,swagger,asyncAPI)

북극곰은콜라 2023. 8. 2. 18:18
반응형


개요

개발 문서 중 API Document를 작성할 방안에 대한 조사 진행
목표는 신뢰성 있으며, 유지보수에 용이한 API 문서 작성이다.
Target API 프로토콜로 REST, RSocket, Kafka Message, Websocket Message 이다.
신뢰성: 문서와 실제 구현상의 간극이 최소화 되는 것을 말함
유지보수 용이: Document 작성을 위한 시간을 최소화 하여, 생산성을 높이는 것, 또한 여러 타입의 문서로 재생산 가능한 것도 포함한다.

 


OpenAPI Specification 이란

OAS란 OpenAPI Specification의 약자로 REST API를 json 또는 yaml로 표현하는 방식에 대한 스펙을 의미한다.
2010년대 초 Tam Wordnik이 개발할 당시에는 Swagger 스펙으로 불리었지만
2015년 즈음 SmartBear에 인수되고, OpenAPI Initiative에 기부되면서 OpenAPI Specification으로 변경 됨
OpenAPI: REST를 정의할 수 있는 스펙
Swagger: OpenAPI 문서를 만들 수 있는 툴 (자동화 목적)

특징

REST API를 문서로 정의 및 생성 할 수 있다.
방대한 생태계 서포트를 통해, REST 문서 관리에 이점이 있다.
스펙 작성을 위한 공식 툴이 존재한다.
스펙을 기반으로 SDK / 코드 생성이 가능한다.
스펙을 기반으로 API 테스트도 가능하다.
오픈 라이센스이다.

OAS 생태계

Swagger UI: OAS를 Web UI로 볼 수 있는 어플리케이션
Swagger Editor: OAS 스펙 편집기, 브라우저 기반
Swagger Codegen: OAS를 기반으로 Server, Client Code 생성
Swagger Spring Integration: Spring 코드에서 OAS 문서를 생성해주는 라이브러리
OpenAPI IDE Plugins: OAS를 위한 IDE 서포트
Swagger Hub: OAS Document를 통한 협업을 손쉽게 진행할 수 있는 서비스

주요 스펙 설명

전체 스펙: https://swagger.io/specification/

 

OpenAPI Specification - Version 3.0.3 | Swagger

OpenAPI Specification Version 3.1.0 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RF

swagger.io

Field Name Type Description
openapi string REQUIRED.
OAS의 스펙 버전, 문서 파싱할 때 참조하기 위한 값
info Info Object REQUIRED.
본 문서를 설명하는 metadata
servers [Server Object] 테스트가 가능한 서버에 대한 정의
paths Paths Object REST Spec에 대한 정의
webhooks Map[string, Path Item Object | Reference Object] ] 콜백을 정의 할 수 있는 파트
components Components Object REST Spec에서 참조하는 객체 정의
security [Security Requirement Object] 인증 및 보안에 관한 스펙
tags [Tag Object] API를 묶을 수 있는 tag를 정의
externalDocs External Documentation Object 외부 문서 링크 등

paths Example

paths:
  /pet/findByStatus:
    get:
      tags:
        - pet
      summary: Finds Pets by status
      description: Multiple status values can be provided with comma separated strings
      operationId: findPetsByStatus
      parameters:
        - name: status
          in: query
          description: Status values that need to be considered for filter
          required: false
          explode: true
          schema:
            type: string
            default: available
            enum:
              - available
              - pending
              - sold
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'          
            application/xml:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
        '400':
          description: Invalid status value
      security:
        - petstore_auth:
            - write:pets
            - read:pets
paths:
  /pet:
    post:
      tags:
        - pet
      summary: Add a new pet to the store
      description: Add a new pet to the store
      operationId: addPet
      requestBody:
        description: Create a new pet in the store
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
          application/xml:
            schema:
              $ref: '#/components/schemas/Pet'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Pet'
        required: true
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'          
            application/xml:
              schema:
                $ref: '#/components/schemas/Pet'
        '405':
          description: Invalid input
      security:
        - petstore_auth:
            - write:pets
            - read:pets

Components Example

components:
  schemas:
    Pet:
      required:
        - name
        - photoUrls
      type: object
      properties:
        id:
          type: integer
          format: int64
          example: 10
        name:
          type: string
          example: doggie
        category:
          $ref: '#/components/schemas/Category'
        photoUrls:
          type: array
          xml:
            wrapped: true
          items:
            type: string
            xml:
              name: photoUrl
        tags:
          type: array
          xml:
            wrapped: true
          items:
            $ref: '#/components/schemas/Tag'
        status:
          type: string
          description: pet status in the store
          enum:
            - available
            - pending
            - sold
      xml:
        name: pet

Spring With Swagger (OAS)

Spring 프로젝트에서 OAS 문서를 만들어 주는 서포트 라이브러리가 있다.
org.springdoc:springdoc-openapi-ui

Sample Code

@Configuration
public class Config {
    @Bean
    public OpenAPI openAPI() {
        return new OpenAPI()
                .info(new Info()
                  .title("...")
                  .description("...")
                  .externalDocs(new ExternalDocumentation()
                    .description("....")
                    .url("http://..."));
    }
}

@OpenAPIDefinition(info = @io.swagger.v3.oas.annotations.info.Info(title = "TEST API", version = "v1"))
@SecurityScheme(
        name = "bearerAuth",
        type = SecuritySchemeType.HTTP,
        bearerFormat = "JWT",
        scheme = "bearer"
)

@Tag(name = "TestAPI", description = "test")

@Operation(summary =  "테스트 기능1, 인증 필요", security = @SecurityRequirement(name = "bearerAuth"))

 


OAS 시각화

Swagger UI

Swagger to Postman

Swagger to Confluence

Swagger2Markup

 


관련 리서치

신뢰성 있는 API 문서란

카카오페이, 토스에서 채택한 방식으로
Integration Test를 통과한 API만 문서가 작성되는 Spring REST Docs를 통해 문서를 생성하여 문서 신뢰도를 확보하고
OAS(Swagger)를 통해 외부 공개 및 API Test 지원

메인 아이디어
- restdocs-api-spec 라이브러리를 통해, Rest Docs를 OAS Document로 변환
- 이 후 프로세스는 동일

MSA 환경에서 문서 배포 자동화

토스의 MSA 환경에서, Swagger를 활용한 문서 자동화 프로세스 정리

메인 아이디어
- Github의 소스코드의 변경이 트리거링 되어, 젠킨스에서 안시블을 통해 문서 자동 생성 및 배포 되는 프로세스
- 개발자는 코드 기반 Docs만 관리하며, 문서 배포가 자동적으로 될 수 있는 기본 프로세스로 보인다.

문서 템플릿 방식

LINE에서 체택한 방식으로
다른 언어, 다른API 유형의 문서를 통합하여 관리 및 게시하기 위한 방식

목적

출력 형식이 바뀌어도 쉽게 적응할 수 있어야 한다.
작성하는 사람이 뭘 써야 하는지 쉽게 알 수 있어야 한다.
다양한 프로그래밍 언어와 API 유형을 통합할 수 있어야 한다.

1. Tool 또는 수기로 API를 작성합니다.
2. 각각의 프로젝트에서 생성된 API를 하나의 Markup 템플릿으로 자동 컨버팅할 수 있도록 합니다.
3. 해당 템플릿으로 여러 타입의 문서를 generate 합니다.
메인 아이디어
- 언어 및 API 유형이 다르면, API 문서를 관리하는 라이브러리 및 Tool이 다를 가능성이 높다.
- 각 API 유형별로 문서가 생성될 수 있다. (같은 기능에 rest와 rsocket으로 제공한다면)
- 이를 해결하기 위해 중간 template을 두고, 최종 문서와 자동 생성되는 문서의 의존성은 낮췄다.
문제점
- 초기 구현 및 검증에 필요한 리소스가 많이 소요될 것으로 예상된다.
- 문서에 필요한 항목 (최종 결과물)에 대한 정의에 리소스가 소요된다.
- 문서 유지관리에 리소스가 소모된다.

 


AsyncAPI

OAS와 유사한 이벤트 드리븐 시스템을 위한 API 스펙
YAML 기반 API Describe 문서
이벤트 드리븐 아키텍쳐를 설명하기 위한 스펙이다.
Protocol에 종속적이지 않다.
Pub / Sub 구조를 정의하기 적합한 스펙

Library Support

Springwolf

// Consumer
@KafkaListener
@AsyncListener(operation = @AsyncOperation(
        channelName = "example-consumer-topic",
        description = "Optional. Customer uploaded an example payload",
        headers = @AsyncOperation.Headers(
                schemaName = "SpringKafkaDefaultHeaders",
                values = {
                        @AsyncOperation.Headers.Header(
                                name = DEFAULT_CLASSID_FIELD_NAME,
                                description = "Spring Type Id Header",
                                value = "io.github.stavshamir.springwolf.example.dtos.ExamplePayloadDto"
                        ),
                }
        )
))
@KafkaAsyncOperationBinding
public void receiveMessage(ExamplePayloadDto msg) {
    // process
}

// Producer
@AsyncPublisher(operation = @AsyncOperation(
        channelName = "example-producer-topic",
        description = "Optional. Customer uploaded an example payload",
        headers = @AsyncOperation.Headers(
                schemaName = "SpringKafkaDefaultHeaders",
                values = {
                        @AsyncOperation.Headers.Header(
                                name = DEFAULT_CLASSID_FIELD_NAME,
                                description = "Spring Type Id Header",
                                value = "io.github.stavshamir.springwolf.example.dtos.ExamplePayloadDto"
                        ),
                }
        )
))
@KafkaAsyncOperationBinding
public void sendMessage(ExamplePayloadDto msg) {
    // send
}

// Message
@AsyncPublisher(operation = @AsyncOperation(
        channelName = "example-producer-topic",
        description = "Optional. Customer uploaded an example payload",
        message = @AsyncMessage(
                messageId = "my-unique-id",
                name = "ExamplePayloadDto",
                schemaFormat = "application/schema+json;version=draft-07",
                description = "Example payload model for sending messages"
        )
))
public void sendMessage(ExamplePayloadDto msg) {
    // send
}

 


요약

1. OpenAPI Specification, Swagger는 REST 프로토콜에 종속적인 API Document 스펙이다.
2. OAS는 REST 프로토콜을 정의하고 활용하기에 좋은 생태계를 가지고 있다.
3. AsyncAPI는 Event-Driven 시스템을 정의할 수 있는 스펙이다.
4. 문서 자동화를 달성 위해서는 파일 기반 Documentation이 효과적이다.
5. json, yaml로 잘 정의된 스펙은 확장성이 뛰어나다.
6. 문서 신뢰성을 위해서는 테스트 기반 문서 생성 프로세스가 필요하다.

 


REFERENCE

https://swagger.io/specification/

https://plugins.jetbrains.com/plugin/8433-openapi-generator

https://engineering.linecorp.com/ko/blog/document-engineering-api-documentation

https://tech.kakaopay.com/post/openapi-documentation/

https://rlxuc0ppd.toastcdn.net/presentation/%5BNHN%20FORWARD%202020%5DMSA%20%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C%20API%20%EB%AC%B8%EC%84%9C%20%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0.pdf

https://www.asyncapi.com/docs/tools/generator/asyncapi-document

https://www.asyncapi.com/tools

https://springwolf.github.io/docs/configuration/documenting-producers/

반응형