TECHSCORE BLOG

クラウドCRMを提供するシナジーマーケティングのエンジニアブログです。

OpenAPIを用いたAPI設計

当社に新卒のバックエンドエンジニアとして入社して約2年が経ちました。Web系の開発に触れたのは入社してからが初めてだったのですが、そこでAPIの設計に使用したOpenAPIについてお話ししようと思います。

林 光希(ハヤシ コウキ)
新卒3年目のバックエンドエンジニアです。
謎解きとゲームが好きで、今はストリートファイター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定義の記述についても学んでみてください。

シナジーマーケティング株式会社では一緒に働く仲間を募集しています。