当社に新卒のバックエンドエンジニアとして入社して約2年が経ちました。Web系の開発に触れたのは入社してからが初めてだったのですが、そこでAPIの設計に使用したOpenAPIについてお話ししようと思います。
謎解きとゲームが好きで、今はストリートファイター6に夢中。
OpenAPIとは
REST APIを記述するためのフォーマットで、yamlかjson形式でAPI定義を記述します。記述したファイルからコードを生成することで、Web APIを簡単に実装できることが特徴です。
OpenAPIを活用するメリット
OpenAPIを活用するメリットは多くありますが、中でも特に大きなメリットだと私が感じる2つを紹介します。
1つ目はバージョン管理やチーム内でのAPI定義の共有が容易になることです。API定義をひとまとまりのテキストファイルで表現するので、gitを用いたバージョン管理が容易に可能で、エンジニア間でAPI定義を共有することも簡単です。
2つ目はAPI定義からAPIのドキュメントを自動生成できることです。Swagger Editorというツールを用いることで、API定義を下図のようにドキュメントで表示することができます。このドキュメントを読むことで、直接API定義の記述されたファイルを読むよりも簡単にAPI定義を理解することができるため、APIの呼び出し部分などを実装するコストが低下します。
基本的な書き方について
本章ではOpenAPIの基本的な書き方について説明します。以下はAPI定義のyamlでの記述例です。各項目について1つずつ述べていきます。
openapi: 3.0.3 info: version: 1.0.0 title: SAMPLE API description: SAMPLE用のAPIです servers: - url: http://sample.local/ description: Development - url: http://localhost:8080/ description: Local paths: /sample/tables/{tableName}/records/{id}: parameters: - $ref: '#/components/parameters/TableName' - name: id in: path description: レコードを識別するID required: true schema: type: integer get: description: id を指定して対象テーブルのレコードを1件取得する。 operationId: getRecord tags: - Record responses: 200: description: OK content: application/json: schema: $ref: "#/components/schemas/RecordResponse" put: description: id を指定して対象のデータを更新する。 operationId: updateRecord tags: - Record requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RecordUpdateRequest' responses: 200: description: OK components: schemas: RecordResponse: type: object required: - record properties: record: type: string RecordUpdateRequest: type: object required: - recordValue properties: recordValue: type: string parameters: TableName: name: tableName in: path description: テーブル名 required: true schema: type: string example: tableName
各項目の説明
info
APIに関する情報を記述する部分です。APIのバージョンや名前、詳細説明を記述できます。
info: version: 1.0.0 title: SAMPLE API description: SAMPLE用のAPIです
servers
APIが動作するサーバ情報を記述する部分です。1つのサーバ情報はURLと詳細説明で構成されており、複数のサーバで動作している場合は複数行に渡って記述できます。
servers: - url: http://sample.local/ description: Development - url: http://localhost:8080/ description: Local
paths
各APIのパスやパラメータ、リクエストメソッドごとのふるまいを記述する部分です。API定義の本体部分と言ってもいいでしょう。
/sample/tables/~のところがAPIへのパスを表します。serversに書いたURLにこちらのパスを結合したものが最終的なAPIのエンドポイントになります。
parametersには定義したAPIで用いるパラメータを記述します。パラメータ名、パスかクエリかといったパラメータ種別、リクエストに必須かどうか、パラメータの型などを定義できます。
get, putといった部分にはエンドポイントに送られてくるリクエストに対するリクエストメソッドごとのふるまいを定義できます。operationIdとtagsにはそれぞれのAPIの名称や分類を記述します。requestBodyとresponsesにはそれぞれリクエストボディとレスポンスの中身をオブジェクトとして定義します。
パラメータ、リクエストボディ、レスポンスはそれぞれオブジェクトとして定義できますが、そのオブジェクトには後述するcomponentsで定義したものを使用することもできます。componentsで定義したオブジェクトを参照する場合は$ref:を用います。
paths: /sample/tables/{tableName}/records/{id}: parameters: - $ref: '#/components/parameters/TableName' - name: id in: path description: レコードを識別するID required: true schema: type: integer get: description: id を指定して対象テーブルのレコードを1件取得する。 operationId: getRecord tags: - Record responses: 200: description: OK content: application/json: schema: $ref: "#/components/schemas/RecordResponse" put: description: id を指定して対象のデータを更新する。 operationId: updateRecord tags: - Record requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RecordUpdateRequest' responses: 200: description: OK
components
API定義内で使用するオブジェクト定義を記述する部分です。componentsの記述はプログラミングでクラス設計をする感覚に近いと思います。
schemasの部分はそれより下のインデント部分にどんな種類のオブジェクトを記述するかを示します。schemasの場合はスキーマオブジェクトになります。schemasの他にもparameters, requestBodies, responsesなどを指定できます。
RecordResponseのようにまずオブジェクト名を書き、その下にオブジェクトが持つプロパティとプロパティに必須条件を付与するかを記述します。
componentsで定義したオブジェクトはAPI定義内で再利用できます。
components: schemas: RecordResponse: type: object required: - record properties: record: type: string RecordUpdateRequest: type: object required: - recordValue properties: recordValue: type: string
おわりに
OpenAPIを用いたAPI定義の記述法について説明しました。今回、説明したものはすべて基本的な記述法ですが、これらを理解することで自分でAPI定義を設計できるのはもちろん、人が書いたAPI定義を読み解く際にも役に立つと思います。この記事を読んで、OpenAPIに興味を持たれた方はぜひより複雑なAPI定義の記述についても学んでみてください。