見出し画像

OpenAPI ドキュメントを分割し、管理を楽にする

🎄この記事はNAVITIME JAPAN Advent Calendar 2023の14日目の記事です。


こんにちは、革靴です。
ナビタイムジャパンで、電鉄・バス事業者向けサービスの開発・運用を担当しています。


はじめに

REST API を開発する際、OpenAPI Specification(以後 OAS と略)の OpenAPI ドキュメントで仕様を定義することが多いと思います。

私はこれまで、OpenAPI ドキュメントは 1 ファイルに全 API の仕様を定義していましたが、API の数や仕様が増えてくると、OpenAPI ドキュメントのファイルサイズが増加し、以下の問題が発生しました。

  • 編集すべき対象箇所を見つけることに時間がかかる

  • 複数人で開発する際、競合が頻発する

これらの問題に対処するために、OpenAPI ドキュメントを分割し、管理するようにしました。今回は、その方法をご紹介します。

OpenAPI ドキュメントの分割方法

OAS のリポジトリに例として上げられている petstore.yaml を使って、ご説明します。

分割後のディレクトリ構成

OpenAPI ドキュメント分割後のディレクトリ構成は、以下のように設計しました。

.
├── parameters          # リクエストパラメーター
│   ├── limit.yaml
│   └── petId.yaml
├── pathItems           # 各 API のエンドポイント
│   ├── pets.yaml
│   └── pets_petId.yaml
├── schemas             # レスポンスボディのスキーマ
│   ├── Error.yaml
│   ├── Pet.yaml
│   └── Pets.yaml
└── root.yaml           # 全体の定義

ディレクトリ名は、OAS のコンポーネントオブジェクトのフィールド名で作成し、1 ファイルの単位は、各コンポーネントオブジェクト単位で記述しました。

分割した各 OpenAPI ドキュメントの中身

root.yaml は OAS のルート定義のみを記述しています。

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
servers:
  - url: http://petstore.swagger.io/v1
paths:
  /pets:
    $ref: ./pathItems/pets.yaml
  /pets/{petId}:
    $ref: ./pathItems/pets_petId.yaml

./paths/pets.yaml はエンドポイント /pets の仕様を記述しています。

get:
  summary: List all pets
  operationId: listPets
  tags:
    - pets
  parameters:
    - $ref: ../parameters/Limit.yaml
  responses:
    "200":
      description: A paged array of pets
      headers:
        x-next:
          description: A link to the next page of responses
          schema:
            type: string
      content:
        application/json:    
          schema:
            $ref: ../schemas/Pets.yaml
    default:
      description: unexpected error
      content:
        application/json:
          schema:
            $ref: ../schemas/Error.yaml
post:
  summary: Create a pet
  operationId: createPets
  tags:
    - pets
  responses:
    "201":
      description: Null response
    default:
      description: unexpected error
      content:
        application/json:
          schema:
            $ref: ../schemas/Error.yaml

./paths/pets_petId.yaml はエンドポイント /pets/{petId} の仕様を記述しています。

get:
  summary: Info for a specific pet
  operationId: showPetById
  tags:
    - pets
  parameters:
    - $ref: ../parameters/PetId.yaml
  responses:
    "200":
      description: Expected response to a valid request
      content:
        application/json:
          schema:
            $ref: ../schemas/Pet.yaml
    default:
      description: unexpected error
      content:
        application/json:
          schema:
            $ref: ../schemas/Error.yaml

./parameters/limit.yaml はエンドポイント /pets で利用するクエリパラメーター limit です。

name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
  type: integer
  maximum: 100
  format: int32

./parameters/petId.yaml はエンドポイント /pets/{petId} で利用するパスパラメーターです。

name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
  type: string

./schemas/Error.yaml は全エンドポイントで共通したエラー時のレスポンスボディのスキーマです。

type: object
required:
  - code
  - message
properties:
  code:
    type: integer
    format: int32
  message:
    type: string

./schemas/Pet.yaml はエンドポイント /pets/{petId} の正常時におけるレスポンスボディのスキーマです。

type: object
required:
  - id
  - name
properties:
  id:
    type: integer
    format: int64
  name:
    type: string
  tag:
    type: string

./schemas/Pets.yaml はエンドポイント /pets の正常時におけるレスポンスボディのスキーマで、配列の要素は ./schemas/Pet.yaml と同じスキーマなので、以下の記述だけで済みます。

type: array
maxItems: 100
items:
  $ref: ./Pet.yaml

分割した各 OpenAPI ドキュメントの中で、$ref というキーワードが登場していますが、こちらは別ファイルになった OpenAPI ドキュメントを参照することができ、相対パスで記述することで認識してくれます。


ファイル分割したことで、1 ファイルあたりのサイズは小さくなりました。
petstore.yaml は 113 行なので、1 ファイルでも、それほど問題は発生しにくいと思いますが、これが数千〜数万行のファイルになってくると、話は変わってきます。

分割した OpenAPI ドキュメントの統合

OpenAPI Specification には、様々な周辺ツールが存在します。

OpenAPI ドキュメントから、コードを生成することについて、こちらの記事でご紹介しているので、良ければご覧ください。

これらのツールを利用する際、OpenAPI ドキュメントを分割したことによる不都合が生じます。

例えば「OpenAPIでコードを生成してスキーマ駆動で開発する:GoとTypeScriptの場合」の記事でご紹介している oapi-codegen はインプットに指定する OpenAPI ドキュメントが 1 ファイルでなければなりません。

皮肉なことに、管理しやすくするために分割した OpenAPI ドキュメントは、周辺ツールを利用する場面では、1 ファイルに統合する必要性が出てくるのです。

分割した OpenAPI ドキュメントを 1 ファイルに統合するために、今回は Redocly CLI というツールを使います。

Redocly CLI

複数の OpenAPI ドキュメントを 1 ファイルに統合するだけなら、Redocly CLI 以外にも、以下のツールが存在します。

しかし、Redocly CLI は統合機能以外にも、様々な機能を兼ね備えている点が魅力的です。いくつか例を上げると、以下になります。

  • OpenAPI ドキュメントから、HTML 形式のドキュメント生成(Redoc

  • OpenAPI ドキュメントの静的解析

インストール方法はいくつかありますが、npm を使うと、以下コマンドになります。

$ npm i -g @redocly/cli@latest

bundle コマンドを使い、先ほど分割した OpenAPI ドキュメントを統合した openapi.yaml を出力できます。

$ redocly bundle root.yaml --output openapi.yaml

Redocly CLI のその他の機能

せっかくなので、先ほど言及した統合以外の機能についても、ご紹介します。

build-doc コマンドを使うと、HTML 形式のドキュメントである Redoc を生成できます。デフォルトでは redoc-static.html というファイル名で出力されます。

$ redocly build-docs root.yaml

lint コマンドを使うと、OpenAPI ドキュメントの静的解析ができます。

$ redocly lint root.yaml

静的解析でよく存在する ignore ルール設定も可能なので、気になる場合は、公式ドキュメントをご覧ください。

まとめ

REST API の開発でよく使われる OpenAPI ドキュメントを分割し、管理しやすくする方法と、分割した OpenAPI ドキュメントを Redocly CLI を使って、統合する方法をご紹介しました。

OpenAPI ドキュメントを各 OAS のコンポーネントオブジェクトで分類し、ファイルサイズを小さくしたことで、API の仕様を特定しやすくなり、競合が発生するリスクも下げることができました。

良ければお試しいただき、REST API の開発・運用が楽になれば幸いです。