🤔

Swaggerのファイル分割を考える

2023/08/03に公開

✅ 目的

Swagger で OpenAPI 仕様(OAS)を定義したいです。
1ファイルで定義するとあっという間に膨大な記述量になり、メンテナンスが難しくなりそうです。
OpenAPI の仕様を元に、メンテナンス性の高い Swagger のファイル分割を考えることがこの記事の目的です。

✅ 対象読者

  • Swagger に入門したい人
  • どうやってファイル分割すれば良いか悩んでいる人

この記事では、以下の記事でまとめたことを前提に執筆します。
Swagger のファイル分割を考えるには、OpenAPI の仕様を理解していることが前提条件です。
https://zenn.dev/mizu4ma/articles/3c29f05ab82739

✅ 結論

以下のような構成になりました。

説明
openapi - - openapi を定義するルートディレクトリ
- openapi.yml - OAS を定義するルートファイル
- paths 各エンドポイントの定義を格納
- - [リソース名] リソース単位でエンドポイントの定義ファイルを格納
- schemas components の schema の定義を格納

公開されている Swagger Editor を元に分割したファイルツリーを以下に記載します。
petのリソースに注目して、詳細を解説します。
https://editor.swagger.io/

openapi/
├── openapi.yml
├── paths
│   ├── pet
│   │   ├── find-by-status.yml
│   │   ├── find-by-tags.yml
│   │   ├── index.yml
│   │   ├── pet-id.yml
│   │   └── upload-image.yml
│   ├── store
│   │   ├── inventory.yml
│   │   ├── order-id.yml
│   │   └── order.yml
│   └── user
│       ├── create-with-list.yml
│       ├── index.yml
│       ├── login.yml
│       ├── logout.yml
│       └── username.yml
└── schemas
    ├── address.yml
    ├── api-response.yml
    ├── category.yml
    ├── customer.yml
    ├── order.yml
    ├── pet.yml
    ├── tag.yml
    └── user.yml

✅ OAS 定義

ルートとなる OpenAPI ドキュメントです。
公式ドキュメントに従ってファイル名はopenapiとします。
https://github.com/mizushima1226/sample-swagger/blob/main/openapi/openapi.yml

ポイントはpathscomponentsの2箇所です。
それぞれ、$refキーワードで外部ファイルを参照しています。
相対パスで参照します。

paths:
  /pet:
    $ref: "paths/pet/index.yml"
  /pet/findByStatus:
    $ref: "paths/pet/find-by-status.yml"
components:
  schemas:
    Address:
      $ref: "schemas/address.yml"
    ApiResponse:
      $ref: "schemas/api-response.yml"
    Category:
      $ref: "schemas/category.yml"

✅ path 定義

ペットを登録・更新するエンドポイントです。
https://github.com/mizushima1226/sample-swagger/blob/main/openapi/paths/pet/index.yml

ID でペットを取得する際のレスポンスは、ペットスキーマ

ペット登録のリクエストボディ・レスポンスともに、コンポーネント化されたペットスキーマを$refで参照しています。

コンポーネントを参照することで、「ペットスキーマにプロパティを追加する」、などの変更をする場合、スキーマを定義している1つのファイルを変更するだけで対応できます。

スキーマ定義は後述します。

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: "../../openapi.yml#/components/schemas/Pet"
    required: true
  responses:
    "200":
      description: Successful operation
      content:
        application/json:
          schema:
            $ref: "../../openapi.yml#/components/schemas/Pet"

✅ schema 定義

ペットスキーマの定義ファイルです。
https://github.com/mizushima1226/sample-swagger/blob/main/openapi/schemas/pet.yml

プロパティの定義は、別のスキーマ定義を$refキーワードで参照可能です。
相対パスで参照します。

tags:
  type: array
  items:
    $ref: "tag.yml"

✅ 【余談】components 参照 vs 外部ファイル直接参照

この記事のサンプルコードでは、openapi.ymlで定義した components を参照しています。
ファイル名の後に#を記述して各フィールドにアクセスします。

responses:
  "200":
    description: Successful operation
    content:
      application/json:
        schema:
          $ref: "../../openapi.yml#/components/schemas/Pet"

componentsを参照するのではなく、次のように外部ファイルを直接参照できます。

responses:
  "200":
    description: Successful operation
    content:
      application/json:
        schema:
-         $ref: "../../openapi.yml#/components/schemas/Pet"
+         $ref: "../../schemas/pet.yml"

執筆時点でどちらの記述が優れているか判断つきませんでした。
OAS を GUI で定義する Spotlight Studio が自動生成した OAS を確認すると、外部ファイルではなく、components を参照していたので、そちらに合わせています。

✅ まとめ

  • pathsschemasからファイル分割を考える
  • 外部ファイルは相対パスで参照するので、ディレクトリ構成を考えるときは注意する

この記事のサンプルコードは以下のリポジトリで公開しています
https://github.com/mizushima1226/sample-swagger

テンプレート用に最小サンプルのブランチを用意しました。
https://github.com/mizushima1226/sample-swagger/tree/template

✅ 感想

最低限のファイル分割を考えることができました。
過度な分割やコンポーネント化は慎重になったほうが良さそうです。
リクエスト・レスポンス定義のコンポーネント化は必要かもしれません。

実践して知見が溜まったり、周りのエンジニア仲間と議論して理解が深まったら、都度この記事を更新していく予定です。

GitHubで編集を提案

Discussion