📄

OpenAPIに入門する

2023/08/01に公開

✅ 目的

Swagger などを使って、API を設計・ドキュメント管理したいです。
一貫性を意識して効率的な API 設計をするためには OpenAPI の概念や仕様を理解する必要があると感じました。

この記事では、OpenAPI に関して調査し、基礎的な部分をまとめます。
この記事を読むことで、次の状態を目指します。

  • OpenAPI の登場人物がわかる
  • OpenAPI 仕様を読める
  • OpenAPI 仕様を書ける
  • OpenAPI の公式ドキュメントを参照できる

✅ 対象読者

  • OpenAPI に入門したい人
  • Swagger を閲覧して、バックエンド・フロントエンド開発したことあるけど、内部的なことをよく知らない人

OpenAPI の概要や周辺ツールについては以下の記事でまとめています。
https://zenn.dev/mizu4ma/articles/08867f5045d237

✅ OpenAPI のサンプル

次のような仕様の API を考えます。

  1. ID を指定して、特定のペットの情報を取得する
  2. ID が未指定の場合、HTTP400 を返却する
  3. 存在しない ID の場合、HTTP404 を返却する
  4. エンドポイントは次の通り:/pets/1

この仕様を OpenAPI 仕様で定義すると以下のようになります。
ここではサラッと読み流して良いです。
この記事を読み終えた時に、読めるようになっているば OK です。

また、OpenAPI 仕様は JSON または YAML 形式で定義します。
この記事のサンプルコードは YAML 形式で記述します。

/pet/{petId}:
  get:
    tags:
      - pet
    summary: Find pet by ID
    description: Returns a single pet
    operationId: getPetById
    parameters:
      - name: petId
        in: path
        description: ID of pet to return
        required: true
        schema:
          type: integer
          format: int64
    responses:
      "200":
        description: successful operation
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Pet"
          application/xml:
            schema:
              $ref: "#/components/schemas/Pet"
      "400":
        description: Invalid ID supplied
      "404":
        description: Pet not found

✅ OpenAPI 仕様の概要

以下の公開されている Swagger Editor にアクセスすると、OpenAPI 仕様の全体像がわかります。

https://editor.swagger.io/

Swagger Editor の 1~43 行目までは、OpenAPI 仕様のメタ情報なので説明を割愛します。
定義を見て、大体どんなことが書いてあるか、程度が分かれば OK。

1~43 行目(一応抜粋)
openapi: 3.0.3
info:
  title: Swagger Petstore - OpenAPI 3.0
  description: >-
    This is a sample Pet Store Server based on the OpenAPI 3.0 specification.
    You can find out more about

    Swagger at [https://swagger.io](https://swagger.io). In the third iteration
    of the pet store, we've switched to the design first approach!

    You can now help us improve the API whether it's by making changes to the
    definition itself or to the code.

    That way, with time, we can improve the API in general, and expose some of
    the new features in OAS3.


    _If you're looking for the Swagger 2.0/OAS 2.0 version of Petstore, then
    click
    [here](https://editor.swagger.io/?url=https://petstore.swagger.io/v2/swagger.yaml).
    Alternatively, you can load via the `Edit > Load Petstore OAS 2.0` menu
    option!_


    Some useful links:

    - [The Pet Store
    repository](https://github.com/swagger-api/swagger-petstore)

    - [The source API definition for the Pet
    Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
  termsOfService: http://swagger.io/terms/
  contact:
    email: apiteam@swagger.io
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 1.0.11
externalDocs:
  description: Find out more about Swagger
  url: http://swagger.io
servers:
  - url: https://petstore3.swagger.io/api/v3

Swagger Editor の OpenAPI 仕様を図示します。
枠の重なりは、同じ構造の繰り返しを意味します。

図で捉えると、大きく3分割できます

  • tags
  • paths
  • components

tags セクション : リソース単位などでタグを作成します。
paths セクション : API 仕様を定義します。
components セクション : コンポーネント化された定義を paths セクションで参照します。

定義をコンポーネント化することで、一貫性を保てます。

各セクションを解説する前に、OpenAPI が扱えるデータ型を紹介します。

✅ OpenAPI が扱えるデータ型

フォーマット 説明
integer int32 符号付 32 bits
integer int64 符号付 64 bits (a.k.a long)
number float
number double
string
boolean
object
array

上記の型を使って API 仕様を定義します。

公式ドキュメント > Data Type
https://spec.openapis.org/oas/latest.html#data-types

✅ tags セクション

タグを定義して、各エンドポイントに紐づけることで、エンドポイントをタグでグルーピングできます。

Swagger UI だと以下のように、グルーピングされます。(pet / store / user)

Image from Gyazo

◼️ Tag Object

以下のような形式で定義します。

name: pet
description: Pets operations

公式ドキュメント > Tag Object
https://spec.openapis.org/oas/latest.html#tag-object

✅ paths セクション

API 仕様を定義するセクションです。

Swagger UI では以下のように可視化されます。
Image from Gyazo

図解した paths セクションを再度添付します。
Image from Gyazo

サンプルの OpenAPI 仕様を元に、説明します。
[]で括られた key は、プレースホルダーを意味します。
value で key の説明をします。

[エンドポイントのパス]:
  [HTTPメソッド]:
    tags:
      - 紐づけるタグ
    summary: エンドポイントの概要
    description: エンドポイントの説明
    operationId: エンドポイントのID
    parameters:
      - name: パラメータ名称
        in: path | query | header | cookie
        description: パラメータの説明
        required: true | false
        schema:
          type: データ型
          format: データフォーマット
    responses:
      [HTTPステータスコード]:
        description: レスポンスの説明
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Pet" (後述するコンポーネントを参照)

補足

  • parameters
    パス・クエリパラメータ、HTTP ヘッダーなどからパラメータを受け取る場合に定義します。
  • in
    • path : /pets/{petId}のように波括弧で括った部分のパスパラメータに対する定義です。
    • query : /pets?category=xxxのようにクエリパラメータに対する定義です。
    • header : 期待するカスタムヘッダーです。ヘッダー名は大文字小文字を区別しないルールとなっています。
    • cookie : API に特定の cookie 値を渡すための設定です。
  • requestBody:リクエストボディからパラメータを受け取る場合に、以下のような形式で定義します。
    requestBody:
      description: Update an existent pet in the store
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Pet"
      required: true
    

公式ドキュメント > Paths Object
https://spec.openapis.org/oas/latest.html#paths-object

✅ components セクション

API 定義をコンポーネント化し、再利用することで一貫性を保ち、効率的に API 仕様を定義できます。

以下のように、様々な種類の API 定義をコンポーネント化できます。
使用頻度の高そうな、schemas / securitySchemesについて説明します。

components:
  schemas:
  responses:
  parameters:
  examples:
  requestBodies:
  headers:
  securitySchemes:
  links:
  callbacks:
  pathItems:

公式ドキュメント > Components Object
https://spec.openapis.org/oas/latest.html#componentsObject

◼️ schemas

以下は、注文スキーマを定義しています。
スキーマ自体のデータ型を指定し、各プロパティのデータ型とサンプル値を定義しています。

注文スキーマを定義することで、注文に関する各エンドポイントのパラメータやレスポンス形式の定義で使い回すことができます。

schemas:
  Order:
    type: object
    properties:
      id:
        type: integer
        format: int64
        example: 10
      petId:
        type: integer
        format: int64
        example: 198772
      quantity:
        type: integer
        format: int32
        example: 7
      shipDate:
        type: string
        format: date-time
      status:
        type: string
        description: Order Status
        example: approved
        enum:
          - placed
          - approved
          - delivered
      complete:
        type: boolean

公式ドキュメント > Schema Object
https://spec.openapis.org/oas/latest.html#schema-object

◼️ securitySchemes

API の認証方式の定義をコンポーネント化します。
以下のような様々な認証方式をサポートしています。

  • Basic 認証
  • API Key 認証
  • JWT Bearer 認証
  • OAuth2.0
  • OpenIDConnect
components:
  securitySchemes:
    jwt:
      type: http
      description: "JWTによる認証です"
      scheme: bearer
      bearerFormat: JWT
    apikey:
      type: apiKey
      description: "API KEYによる認証です"
      in: header
      name: x-api-key

公式ドキュメント > Security Scheme Object
https://spec.openapis.org/oas/latest.html#securitySchemeObject

✅ まとめ

  • OpenAPI 仕様は JSON または YAML 形式で記述する
  • tags でリソース名を定義しエンドポイントをグルーピングできる
  • paths で各エンドポイントの仕様を定義する
  • components で API 仕様をコンポーネント化し、再利用することで一貫性を保ち、効率的に API 設計できる

✅ 感想

本記事をまとめることで、主な登場人物とその関係の理解が深まりました。

Swagger などで OpenAPI 仕様を定義する際、1つのファイルで定義すると膨大な行数になって可読性・メンテナンス性が悪くなることは明らかです。

ので、ディレクトリ構成とファイル分割を工夫する必要があると思います。
OpenAPI の構造を理解することは、ディレクトリ構成やファイル分割を考える手助けになると思いました。

構造を理解せずにディレクトリ構成を考えたり、API 仕様を定義し始めると、あっという間に難解な OpenAPI 仕様が出来上がる未来が見えました。

また、無闇なコンポーネント分割は返ってメンテナンス性や可読性を低下させそうな雰囲気を感じます。
適度な分割点を探るのがポイントになってきそうです。

ここら辺は、実践しながら知見を深めていきたいです。

GitHubで編集を提案

Discussion