計画と改善

エンジニアのブログ

OpenAPI再入門

OpenAPIとは?

RESTFul APIの仕様のこと。略語はOAS。今回確認したのは最新のVersion 3.0.3。yamlもしくはjsonファイルで記述し、APIの仕様を定義することができる。

スキーマと呼ばれるオブジェクト(データモデル)が存在し、各オブジェクトでどのようなフィールドを持つことができるのかはドキュメントのFixed Fieldsの欄で確認することができる。

オブジェクトの一部のフィールドには接頭辞のx-をつけることでベンダー独自の仕様拡張が可能となっている。拡張可能なフィールドに関してもopenapiの仕様書に定義されている。

構造

ルートの定義

APIのルートパスに関してはopenapiのスキーマであるServerオブジェクトで定義する。urldescriptionがserverオブジェクトのフィールドにあたる。

以下のように複数の環境を定義できる。

servers:
  - url: http://api.example.com/v1
    description: "本番環境"
  - url: http://staging-api.example.com
    description: "ステージング環境" 

このurlフィールドの定義はサーバーのベースパスとなる。

urlフィールドの任意の部分には変数を渡すこともできる。変数を渡したいときはvariablesフィールドに必須のdefaultフィールドを設定し、オプションのenumをセットする。

servers:
  - url: '{protocol}://api.example.com'
    variables:
      protocol:
        enum:
          - http
          - https
        default: https

全てのスキーマに対して言えることだが、Fixed Fieldstype(データ型)に他のオブジェクトが設定されていた場合、そのフィールドは他のオブジェクトを持つことができる。(オブジェクトは定義に従った入れ子構造にできる)

例えばServerオブジェクトのフィールドにはvariablesフィールドが定義されているが、これはServer Variableオブジェクトという別のオブジェクトであり、Server Variableオブジェクトがどのようなフィールドを持つことができるかはServer VariableオブジェクトのFixed Fieldsに従う。

その他のOASのプリミティブなデータ型についてはJSON Schema Specification Wright Draft 00 でサポートされている型に基づいている。

Paths

エンドポイントに対して、複数のHTTPメソッド(操作)を定義できる。

例:

paths:
    /users/{id}:
        get:
          ...
        patch:
          ...
        delete:
          ...

エンドポイント

フィールド名は/で始まる必要がある。このエンドポイントはベースURLに対して相対的なもの。

例えばエンドポイントを/usersのように設定し、serverのベースURLをhttps://api.example.com/v1のように設定している場合、エンドポイントはhttps://api.example.com/v1/usersとして参照される。{id}のように中括弧を利用してURLの一部をパスパラメータとして利用することもできる(パステンプレート)。その場合、APIクライアントはhttps://api.example.com/v1/users/5などと適切なパラメータを提供する必要がある。

HTTPメソッド(操作)

GET、POST、DELETE などのHTTPメソッド。

また、OpenAPIの「操作(operations)」の定義にはパラメータ、リクエストボディ、レスポンスのステータスコード(200 OK または 404 Not Found など)、レスポンスの内容が含まれる。

Pathの定義と入れ子構造

Pathの項目でパラメータ、レスポンス、ステータスコードを定義した場合、以下のような形になる

paths:
  /users/{id}:
    get:
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
      required:
        - id
        - name

それぞれのフィールドを分解してコメントを入れるとこんな感じ。

paths: # pathsオブジェクト
  /users/{id}: # pathオブジェクトのフィールド(Path Itemオブジェクト)
    get: # Path Itemオブジェクトのフィールド(Operationオブジェクト)
      parameters: # Operationオブジェクトのフィールド(Parameterオブジェクト)
        - name: id # Parameterオブジェクトのフィールド(string)
          in: path # Parameterオブジェクトのフィールド(string)
          required: true # Parameterオブジェクトのフィールド(boolean)
          schema: # Parameterオブジェクトのフィールド(Schemaオブジェクト)
            type: integer # Schemaオブジェクトのプロパティ
            format: int64 # Schemaオブジェクトのプロパティ
      responses: # Operationオブジェクトのフィールド(Responsesオブジェクト)
        '200': # Responsesオブジェクトのフィールド(Responseオブジェクト)
          content: # Responseオブジェクトのフィールド(Map[string, Media Typeオブジェクト])
            application/json: # Map[string, Media Typeオブジェクト]型のキー(string)
              schema: # Media Typeオブジェクト型のフィールド(Schemaオブジェクト)
                $ref: '#/components/schemas/User' # Referenceオブジェクト
...
components: # Componentsオブジェクト
  schemas: # Componentsオブジェクトのフィールド(Map[string, Schemaオブジェクト])
    User: # Map[string, Schemaオブジェクト]型のキー(string)
      type: object # Schemaオブジェクトのプロパティ
      properties: # Schemaオブジェクトのプロパティ
        id: # Schemaオブジェクト
          type: integer # Schemaプロパティ
          format: int64 # Schemaプロパティ
        name: # Schemaオブジェクト
          type: string # Schemaプロパティ
      required: # Schemaオブジェクトのプロパティ
        - id
        - name

※Schemaオブジェクトに関してはフィールドという表現ではなく、プロパティという表現になっている。こちらのプロパティについてもJson Schemaに基づき定義されている。