はじめに

はじめまして。デザイン&エンジニアリング部の渡邊です。

本記事では案件での OpenAPI の使用経験を元に、OpenAPI で REST API 定義の作成方法をご紹介します。Stoplight Studio という GUI ツールを用いることで、OpenAPI 初心者の方でも簡単に OpenAPI の定義ファイルを作成できます。これから OpenAPI を導入してみたい方や、OpenAPI がどのようなものか知りたい方を中心に活用していただけたら幸いです。

OpenAPI とは

OpenAPI [1] は、REST API の仕様を記述するための標準フォーマットであり、YAML または JSON 形式で API を定義できます。OpenAPI の定義ファイル(以下「OpenAPI 定義」と呼ぶ)には主に下記の仕様を記述します。

  • API のエンドポイント
  • HTTP メソッド
  • リクエスト・レスポンス

作成した OpenAPI 定義からソースコード・テストコード・ドキュメントなどを生成することができ、さまざまな開発プロセスを自動化できます。

OpenAPI の導入理由

私が参画した案件で OpenAPI を導入した理由を説明します。

1点目は開発コストを削減できる点です。私の参画していた案件では SPA 構成の Web アプリケーションを開発していたため、フロントエンド側で API 呼び出しのコードを API ごとに実装する必要があります。OpenAPI を導入する前は、これを手動で一から実装していました。しかし、OpenAPI の導入により OpenAPI 定義からAPI 呼び出しのコードを自動生成することができるようになり、単純作業を減らすことでコストを削減できました。

2点目はフロントエンドとバックエンド間でインターフェースの整合性を保てる点です。OpenAPI 定義からバックエンドのソースコードも自動生成できます。そのため、フロントエンド・バックエンド共に同じ OpenAPI 定義からソースコードを生成することができ、インターフェースの不整合を防ぐことができます。

OpenAPI の構成要素

OpenAPI 定義の構成について、下記のサンプルを元に説明します。

※本記事では全て YAML 形式で記述しています。

openapi: 3.0.0
info:
  title: Sample APIs
  version: 1.0.0
servers:
  - url: http://localhost:8080
paths:
  /sample:
    get:
      summary: サンプル取得API
      tags:
        - sample
      operationId: get-sample
      description: サンプルを取得します
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
components: {}
tags:
  - name: sample

 

OpenAPI 定義を構成する主要なフィールドについて説明します。各フィールドで定義する内容は下記の通りです [2]

※他にも様々なフィールドが存在しますが、本記事では割愛します。

フィールド 必須 説明
openapi OpenAPI のバージョン
info API に関するメタデータ
servers API をホストするサーバーの URL
paths 各 API のエンドポイントと API の詳細(HTTP メソッド・リクエスト・レスポンスなど)
components API 内で再利用可能なパラメータ・リクエスト・レスポンスなど
tags API のエンドポイントを分類するためのタグ

paths 以外のフィールドは各 API で共通の情報を記述し、paths フィールドには各 API の詳細情報を記述します。サンプルでは paths にサンプル取得 API(GET /sample )のみが定義されています。paths 内のフィールドや components については「OpenAPI 定義を作成してみる」で詳しく説明します。

 

下記の定義は OpenAPI の最小構成 [3] を示しています。必須フィールドのみが記述されており、ここから必要に応じてフィールドを追加していくことができます。

openapi: 3.0.0
info:
  title: A minimal OpenAPI Description
  version: 0.0.1
paths: {}

OpenAPI 定義を作成してみる

サンプルで用意した API の情報を元に、OpenAPI 定義を作成する方法をご紹介します。案件でも導入している Stoplight Studio というツールを用いて OpenAPI 定義を作成していきます。

Stoplight Studio とは

Stoplight Studio [4] は、OpenAPI 定義を GUI で編集できるツールです。YAML や JSON 形式に慣れていない方でも画面から直感的に OpenAPI 定義を作成することが可能です。無料版も用意されているので、気軽に導入できます [5]

定義対象 API

今回はアカウント情報の操作に関する REST API を定義します。この中から「アカウント一覧取得 API」「アカウント更新 API」の定義方法について紹介します。残りの API については説明を割愛しますが、作成した OpenAPI 定義を記事の末尾に載せています。

API 名 HTTP

メソッド

エンドポイント 説明 リクエスト レスポンス
アカウント一覧取得 API GET /accounts アカウント情報を全て取得する アカウント情報の一覧
アカウント登録 API POST /accounts アカウント情報を新規登録する アカウント情報 登録したアカウント情報
アカウント更新 API PUT /accounts/{accountId} アカウント情報を更新する アカウント情報 更新したアカウント情報
アカウント削除 API DELETE /accounts/{accountId} アカウント情報を削除する

 

アカウント情報は下記の項目が含まれている想定とします。

項目名(論理名) 項目名(物理名)
アカウントID accountId
氏名 name
メールアドレス mail
住所 address
バージョン version

 

アカウント一覧取得 API

本記事では、各 API で定義する内容を下記の3つに分けています。

  • API 概要
  • リクエスト
  • レスポンス

それぞれについて Stoplight Studio で定義した内容をお見せし、各設定項目を説明していきます。

 

▼API概要

 

各設定項目は下記の通りです。

対応する

フィールド

説明 設定値 補足
1 tags API を分類するためのタグ 「accounts」 今回はアカウント情報に関する API のため、エンドポイントと同じ名前を設定
2 summary API 名 「アカウント一覧API」
3 エンドポイント 「/accounts」
4 HTTP メソッド 「GET」
5 operationId API を一意に識別するための文字列 「get-accounts」 Stoplight Studio によって自動入力された値を使用(HTTP メソッドとエンドポイントをハイフンでつなげた値)

OpenAPI 定義からソースコードを自動生成する際、operationId を元に生成される関数やメソッドの名前が決まる

6 description API の説明 「アカウント情報を全て取得する」

ここでは「定義対象 API」に記載された情報を機械的に入力していくことで、定義を作成できます。tags や operationId にも入力ルールを定めておくことで、統一された定義を作成できます。

 

▼リクエスト

アカウント一覧取得 API はリクエスト項目がないため、設定する項目はありません。

 

▼レスポンス

 

各設定項目は下記の通りです。

対応する

フィールド

説明 設定値 補足
1 ステータスコード 「200」 今回は正常系のレスポンスを定義するため「200」を設定

異常系のレスポンスを定義する場合は「+Response」ボタンからステータスコードを追加可能

2 description レスポンスの説明 「OK」 Stoplight Studio によって自動入力された値を使用
3 レスポンスの形式 「application/json」 JSON 形式でレスポンスする想定
4 schema レスポンス項目 ※画像参照 アカウント情報の各項目を設定(物理名と型)

一覧取得 API であるため、配列でアカウント情報をレスポンスする

5 required 必須選択 ※画像参照 必須の項目を選択

address 以外は必須項目の想定

 

ここでの設定では、下記のような JSON がレスポンスされることを定義しています。

{
  "accountList": [
    {
      "accountId": "account-01",
      "name": "Alice",
      "email": "alice@example.com",
      "address": "America"
      "version": 3
    },
    {
      "accountId": "account-02",
      "name": "Bob",
      "email": "bob@example.com",
      "version": 5
    }
  ]
}

 

▼作成された OpenAPI 定義
Stoplight Studio で設定した内容は、下記の OpenAPI 定義となります。
paths:
  /accounts:
    get:
      summary: アカウント一覧取得API
      tags:
        - accounts
      operationId: get-accounts
      description: アカウント情報を全て取得する
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  accountList:
                    type: array
                    items:
                      type: object
                      properties:
                        accountId:
                          type: string
                        name:
                          type: string
                        mail:
                          type: string
                        address:
                          type: string
                        version:
                          type: integer
                      required:
                        - accountId
                        - name
                        - mail
                        - version
                required:
                  - accountList
※paths 以外のフィールドは省略しています。
※Stoplight Studio を使用すると、編集した項目に「x-stoplight」というフィールドが付与されますが、読みやすさのために除いています。(x-stoplight は Stoplight Studio 独自の拡張フィールドであり、OpenAPI の仕様には影響しません [6] 。)

 

以上でアカウント一覧取得 API の OpenAPI 定義は完成です。

アカウント更新 API

続いて、アカウント更新 API のOpenAPI定義を作成していきます。

 

▼API概要

アカウント更新 API のエンドポイントにはパスパラメータが含まれており、波括弧で囲うことで、Stoplight Studio にパスパラメータとして認識されます。他の項目については、アカウント一覧取得 API と同様に設定します。

 

▼リクエスト

リクエストの項目はレスポンスと同様に設定できます。

 

▼レスポンス

アカウント一覧取得 API と同様に設定します。(アカウント更新 API は1件のみアカウント情報をレスポンスします。)

 

▼作成された OpenAPI 定義

paths:
  "/accounts/{accountId}":
    parameters:
      - schema:
          type: string
        name: accountId
        in: path
        required: true
    put:
      summary: アカウント更新API
      tags:
        - accounts
      operationId: put-accounts-accountId
      description: アカウント情報を更新する
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                mail:
                  type: string
                address:
                  type: string
                version:
                  type: integer
              required:
                - name
                - mail
                - version
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  accountId:
                    type: string
                  name:
                    type: string
                  mail:
                    type: string
                  address:
                    type: string
                  version:
                    type: integer
                required:
                  - accountId
                  - name
                  - mail
                  - version

 

リファクタリング

ここまでアカウント一覧取得 API・アカウント更新 API の定義を作成しましたが、両 API のレスポンスのアカウント情報は同一であることが分かります。そこで、「OpenAPI の構成要素」で説明した components フィールドを使用してアカウント情報の型を共通化させます。

 

▼共通のレスポンス型

Stoplight Studio の「Models」から「ResAccounts」という名前のレスポンス型を追加します。Models に追加した項目は、OpenAPI 定義の components フィールド内の「schemas」フィールドに追加されます。

このレスポンスを使用してアカウント一覧取得 API・アカウント更新 API のレスポンスを共通化させると下記のようになります。

 

▼アカウント一覧 API のレスポンス

 

▼アカウント更新 API のレスポンス

 

▼作成された OpenAPI 定義

paths:
  /accounts:
    get:
      summary: アカウント一覧取得API
      tags:
        - accounts
      operationId: get-accounts
      description: アカウント情報を全て取得する
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  accountList:
                    type: array
                    items:
                      $ref: "#/components/schemas/ResAccounts"
                required:
                  - accountList
  "/accounts/{accountId}":
    parameters:
      - schema:
          type: string
        name: accountId
        in: path
        required: true
    put:
      summary: アカウント更新API
      tags:
        - accounts
      operationId: put-accounts-accountId
      description: アカウント情報を更新する
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                mail:
                  type: string
                address:
                  type: string
                version:
                  type: integer
              required:
                - name
                - mail
                - version
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResAccounts"
components:
  schemas:
    ResAccounts:
      title: ResAccounts
      type: object
      properties:
        accountId:
          type: string
        name:
          type: string
        email:
          type: string
        address:
          type: string
        version:
          type: integer
      required:
        - accountId
        - name
        - email
        - version

このように components フィールドで定義した型は paths フィールド内から参照できます。

レスポンス以外にも、ドメインの型を定義して各項目に紐づけることや、パスパラメータやクエリパラメータを共通的に定義することなどもできます。保守性向上のため、共通化できる項目は components フィールドに定義しておくことをおすすめします。

OpenAPI 定義からドキュメントを生成してみる

OpenAPI 定義を作成してみる」で作成した OpenAPI 定義を元にドキュメントを生成します。ドキュメント生成には Redocly の build-docs コマンド [7] を使用します。

redocly build-docs [OpenAPI定義のパス] -o [出力先パス]

-o オプションを使用することで出力先パスを指定できます [8]

 

コマンドを実行すると、下記のドキュメントが生成されます。

各 API に accounts タグを付与していることにより、タグごとに API が分類されています。各 API については、OpenAPI 定義で記述した内容を細かく整理された状態で表示できます。ソースコードの自動生成と組み合わせることで、実装とドキュメントの整合性を保つことが容易になります。

ソースコードの自動生成

OpenAPI 定義からソースコードを自動生成する方法については、Fintan の下記記事で紹介されています。これから OpenAPI を導入する方の参考になると思いますので、是非ご覧ください。

OpenAPI の注意点

Git で OpenAPI 定義を管理している場合、ファイルのコンフリクトに注意する必要があります。異なるブランチで異なる API の定義を追加すると、マージした際に高確率でコンフリクトが発生してしまいます。場合によっては絡まった糸を解くような修正をする必要があり、API 定義を作成するのに費やした時間と同じくらいコンフリクト解消に時間がかかることもあります。

 

アカウント一覧取得 API とアカウント更新 API の定義を別ブランチで作成してマージさせた場合

この課題に対して私の案件では、「最初に全ての API を仮定義する」という方法を取り、コンフリクトを回避しました。具体的には、各 API のエンドポイントと HTTP メソッドのみを OpenAPI 定義に記述してマージし、その後に各作業者が異なるブランチで各 API の定義を記述するという方法です。複数人で作業する際には効果的なので、是非参考にしてみてください。

Stoplight Studio の注意点

Stoplight Studio を介さずにOpenAPI 定義を直接編集する場合は注意が必要です。Stoplight Studio には下記の特徴があります。

  • Stoplight Studio 上の修正 → OpenAPI 定義に即時反映される
  • OpenAPI 定義上の修正 → Stoplight Studio を開き直すまで反映されない

そのため、OpenAPI 定義を直接編集した後に Stoplight Studio を開き直さず編集した場合、OpenAPI 定義を直接編集した内容が失われてしまいます。Stoplight Studio を利用していても、YAML 形式で編集した方が都合がよい場合もありますので、その際は忘れずに Stoplight Studio を開き直すように注意してください。また、Stoplight Studio には GUI 以外に YAML 形式で修正できる機能も備わっているので、その機能を使うことで Stoplight Studio を開き直すことなく YAML 形式の修正が可能です [9]

まとめ

OpenAPI を使用した REST API の定義方法と OpenAPI 定義からドキュメントを生成する方法について説明しました。Stoplight Studio を利用することで、OpenAPI 初心者の方でも簡単に OpenAPI 定義を作成できることがお分かりいただけたと思います。これから OpenAPI を導入される方の参考になれば幸いです。

また、「OpenAPI 定義を作成してみる」で作成した OpenAPI 定義の全量を次のページに公開していますので、興味のある方は是非ご覧ください。

参考文献

  1. What is OpenAPI? | Swagger
  2. Schema | OPENAPI INITIATIVE
  3. Minimal OpenAPI Description Structure | OPENAPI INITIATIVE
  4. What is Stoplight Platform? | Stoplight
  5. API Design Plans and Pricing | Stoplight
  6. Extensions | Stoplight
  7. build-docs | Redocly
  8. build-docs Options | Redocly
  9. Design Editor Overview | Stoplight