OpenAPIとは
RESTfulなWebサービスを記述、生成、利用、可視化するためのインターフェースファイルの仕様です。
以前はSwaggerフレームワークの一部でしたが、2016年にOpenAPI Initiativeが統括する独立プロジェクトとなりました。
Swaggerや他のいくつかのツールは、インターフェースファイルを指定してコード、ドキュメント、テストケースを生成することが可能です。
OpenAPIの正確な仕様については、↓から確認できます。
https://swagger.io/specification/
プロジェクトでの利用法
プレセナの一部プロジェクトでは、API定義をOpenAPI仕様に従って記述するだけでなく、定義ファイル(openapi.yaml)からコードを自動生成して利用しています。
OpenAPI定義ファイルの分割
肥大化するopenapi.yaml
当初はAPI定義ファイルであるopenapi.yamlの1ファイルに全ての記述をしていました。
結果として、下記のような問題が発生しました。
- ファイルサイズの増加(約2500行)
- コンフリクトの頻発
- 編集すべき記述を素早く見つけられない
これらの問題に対処するためにopenapi.yamlの分割をおこなうことにしました。
openapi.yamlファイルの構成
openapi.yamlのファイルは大きく分けると下の様なブロックに分かれています。
- バージョン情報といったメタ情報:info、serversなど
- エンドポイントのURLやリクエスト/レスポンス情報:paths
- 再利用可能なオブジェクト情報:components
openapi: "3.0.0" info: version: 1.0.0 title: Swagger Petstore license: name: MIT servers: - url: http://petstore.swagger.io/v1 paths: /pets: get: summary: List all pets operationId: listPets tags: - pets parameters: - name: limit in: query description: How many items to return at one time (max 100) required: false schema: type: integer format: int32 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: "#/components/schemas/Pets" ・・・略・・・ components: schemas: Pet: type: object required: - id - name properties: id: type: integer format: int64 name: type: string tag: type: string Pets: type: array items: $ref: "#/components/schemas/Pet" ・・・略・・・
主に記述量が肥大化してしまうのは pathsとcomponentsであったため、これらを別ファイルに分割しました。
ファイルの分割
ファイルの分割は簡単です。
定義内の他コンポーネントを参照できるようにするフィールドである$ref
を相対パスで記述するだけです。
openapi.yaml
...(infoやserversは省略)... paths: /pet: $ref: "./paths/pet.yaml" /pet/{petId}/upload-image: $ref: "./paths/upload-image.yaml"
/paths/pet.yaml
get: summary: List all pets operationId: listPets tags: - pets parameters: - name: limit in: query required: false schema: type: integer format: int32 responses: '200': content: application/json: schema: $ref: "../schemas/Pet" # $refの記述 default: description: unexpected error content: application/json: schema: $ref: "../schemas/Error" # $refの記述
/schemas/Pet.yaml
Pet: type: object required: - id - name properties: id: type: integer format: int64 name: type: string tag: type: string
フォルダ構造
openapi.yamlをルートファイルとして、同階層にpathとschemasのフォルダを作成しました。
. ├── openapi.yaml ├── paths # pathの定義ファイルを置く │ ├── pet.yaml │ ├── pet_find-by-status.yaml │ ├── ... │ └── pet_petId_upload-image.yaml └── schemas # schemasの定義ファイルを置く ├── Pet.yaml ├── User.yaml ├── ... └── Tag.yaml
paths配下のファイルの命名規則としては、シンプルにエンドポイントURLの「/」を「_」にするファイル名としました。
/paths/pet/find-by-status.yaml
のように階層を深くするアイデアもあったのですが、schemasへの参照を$ref
で記述する際、"../../schemas/Foo"
, "../../../schemas/Bar"
のように 「..」を書く回数の混乱が生じないように現在のような命名規則をとりました。
エンドポイントURLにidが含まれる場合(ex. /pet/{petId}/upload-image)、理想的にはpet_[petId]_upload-image.yaml
のようにしたかったのですが、 []
を含むと自動生成コードで問題が生じたため、シンプルにpet_petId_upload-image.yaml
としました。
まとめ
分割によって見通しがよく開発をすすめることができるようになりました。
Visual Studio Codeで開発しているなら、この拡張をいれることで$ref
の記述からファイル参照もできるのでおすすめです。
https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi
しばらくこれで開発を進めてみて、課題感がまた出てきたらブラッシュアップしていきたいと思います。