OpenAPIとは、REST APIの仕様(URL、パラメーター、リクエスト、レスポンス、認証など)を、YAMLやJSONで記述するための標準の形式です。以前は「Swagger」と呼ばれていました。OpenAPIで仕様書を書いておくと、見やすいドキュメントの自動生成、クライアントやサーバーのコードの生成、仕様どおりかのテストまで、さまざまなツールで活用できます。

この記事では、注文APIを例に、そのまま使えるYAMLのテンプレートで書き方を解説します。テンプレートは、OpenAPIのリンター(Redocly CLI)で検査し、エラーがないことを確認しています。後半では、リントやドキュメントの生成を含めた、チームで仕様書を使い続けるための運用も紹介します。

OpenAPIの構造の早見表

項目 役割
openapi OpenAPIのバージョン(3.1.1 など)
info APIの名前・バージョン・説明
servers APIのURL(本番・検証など)
security API全体に適用する認証
tags エンドポイントのグループ分け
paths エンドポイント(URL×HTTPメソッド)ごとの定義
components 使い回す部品(スキーマ、レスポンス、パラメーター、認証方式)
$ref components の部品を参照する

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「OpenAPIの書き方|YAMLのテンプレートとチームで使う運用」

テンプレート:注文API

注文の作成と取得を行うAPIの定義です。Redocly CLIでの検査結果は「valid(エラーなし)」でした。

openapi: 3.1.1
info:
  title: 注文API
  version: 1.0.0
  description: 注文の作成・取得を行うAPIです。
servers:
  - url: https://api.example.com/v1
    description: 本番環境
security:
  - bearerAuth: []
tags:
  - name: orders
    description: 注文
paths:
  /orders:
    post:
      tags: [orders]
      operationId: createOrder
      summary: 注文を作成する
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderCreate'
            example:
              item: マウス
              quantity: 2
      responses:
        '201':
          description: 作成された注文
          headers:
            Location:
              description: 作成された注文のURL
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /orders/{orderId}:
    get:
      tags: [orders]
      operationId: getOrder
      summary: 注文を1件取得する
      parameters:
        - name: orderId
          in: path
          required: true
          description: 注文ID
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        '200':
          description: 注文
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    OrderStatus:
      type: string
      enum: [pending, paid, shipped, cancelled]
    Order:
      type: object
      required: [id, item, quantity, status]
      properties:
        id:
          type: integer
          format: int64
          example: 123
        item:
          type: string
          example: マウス
        quantity:
          type: integer
          minimum: 1
          example: 2
        status:
          $ref: '#/components/schemas/OrderStatus'
    OrderCreate:
      type: object
      required: [item, quantity]
      properties:
        item:
          type: string
          minLength: 1
          maxLength: 100
        quantity:
          type: integer
          minimum: 1
          maximum: 99
    Problem:
      type: object
      description: RFC 9457 のエラー形式
      required: [type, title, status]
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        errors:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
              message:
                type: string
  responses:
    Unauthorized:
      description: 認証されていません
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    NotFound:
      description: リソースが存在しません
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    ValidationError:
      description: 入力内容に誤りがあります
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'

書き方のポイント

paths:URLとメソッドごとに書く

paths:
  /orders/{orderId}:
    get:
      operationId: getOrder
      summary: 注文を1件取得する
項目 内容
operationId 操作の一意の名前。コード生成のときにメソッド名になる。API全体で重複させない
summary 一覧に表示される短い説明
description 詳しい説明(Markdownが使える)
tags ドキュメントでのグループ分け

parameters:どこに値を入れるか

in の値 場所 例
path URLの一部 /orders/{orderId} の orderId(required: true が必須)
query ? 以降 /orders?status=paid
header HTTPヘッダー Idempotency-Key
cookie Cookie セッションID

schemas:データの形と制約

キーワード 意味
type string・integer・number・boolean・object・array
required 必須の項目の一覧
enum 取りうる値の一覧
minLength / maxLength 文字数の範囲
minimum / maximum 数値の範囲
format int64、date-time、email、uri など
example 例の値。ドキュメントやモックサーバーで使われる

制約(必須・範囲・形式)まで書いておくと、仕様書を見ただけで入力チェックのルールがわかり、仕様書からバリデーションのコードやテストを作ることもできます。

components と $ref:同じものを2回書かない

注文のデータ(Order)や、エラーのレスポンス(NotFound)は、複数のエンドポイントで使います。components に1回だけ定義し、$ref で参照します。

responses:
  '404':
    $ref: '#/components/responses/NotFound'

同じ定義をコピーすると、片方だけ直して食い違う原因になります。2回以上使うものは、components にまとめます。

認証:securitySchemes

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
security:
  - bearerAuth: []
認証方式 書き方
Bearerトークン(JWTなど) type: http + scheme: bearer
APIキー(ヘッダー) type: apiKey + in: header + name: X-API-Key
OAuth 2.0 type: oauth2 + flows
OpenID Connect type: openIdConnect + openIdConnectUrl

ルートの security はAPI全体に適用されます。ログインのように認証が不要なエンドポイントでは、そのエンドポイントに security: [] と書いて外します。

エラーの形式を揃える:RFC 9457

テンプレートでは、エラーのレスポンスを application/problem+json(RFC 9457の形式)で定義しています。すべてのエラーを同じ Problem スキーマで返すと決めておくと、画面側で共通のエラー処理が書けます。

リントで間違いを見つける

OpenAPIのファイルは長くなりやすく、手で書くと間違いが混ざります。リンターを使うと、機械的に見つけられます。

npx @redocly/cli lint openapi.yaml

テンプレートに、わざと2つの間違いを入れて検査した結果です。

Can't resolve $ref
Every operation must have a unique `operationId`.
❌ Validation failed with 2 errors and 3 warnings.
入れた間違い 検出された内容
$ref のスキーマ名の打ち間違い(OrderCreat) 参照先が見つからない
operationId の重複 operationIdは一意でなければならない

リンターには、プロジェクト独自のルール(「すべてのエンドポイントに説明を書く」「URLは複数形の名詞にする」など)を追加することもできます。CIで毎回実行すると、仕様書の品質を保てます。

ドキュメントとして表示する

ツール 特徴
Swagger UI ブラウザで仕様を表示し、その場でAPIを試せる
Redoc(Redocly) 読みやすい1ページのドキュメントを生成する
エディターの拡張機能 VS Codeなどで、書きながらプレビューできる
npx @redocly/cli build-docs openapi.yaml -o docs.html

実際に、この形式の仕様書から、1ファイルのHTMLドキュメントが生成できることを確認しました。

コードを生成する

ツール できること
OpenAPI Generator Java・TypeScript・Pythonなど多くの言語で、クライアントやサーバーの雛形を生成
openapi-typescript TypeScriptの型定義を生成
springdoc-openapi 逆方向。Spring BootのコードからOpenAPIの仕様書を生成

設計を先に書くか、コードから作るか

方式 流れ 向いている場面
設計ファースト 仕様書を先に書き、レビューしてから実装する 画面とAPIを並行して作る、外部に公開する、チームが分かれている
コードファースト コードを書き、仕様書を自動生成する 小規模、実装とAPIの形がほぼ同じ

画面の開発者とAPIの開発者が別々の場合は、設計ファーストがおすすめです。仕様書が決まれば、モックサーバーを立てて、APIの完成を待たずに画面の開発を始められます。

チームで使い続けるための運用

ルール 内容
仕様書をGitで管理する コードと同じリポジトリに置き、変更をプルリクエストでレビューする
CIでリントする 間違いや、ルールに反した書き方をマージ前に見つける
仕様書と実装のずれを検査する 実装から生成した仕様書と比べる、仕様をもとにしたテストを実行する
大きいファイルは分割する paths/・schemas/ などに分け、$ref でファイルをまたいで参照する
変更の影響を確認する 項目の削除・型の変更は、既存の利用者が動かなくなる変更として扱う

OpenAPIのバージョンの違い

バージョン 主な特徴
2.0(Swagger 2.0) 旧形式。definitions など書き方が異なる
3.0 components の導入など、現在の書き方の基本
3.1 JSON Schemaとの互換性が向上。nullable の代わりに type: [string, 'null'] と書く
3.2 さらに新しい版。ツールの対応状況を確認してから使う

新しく書くなら、多くのツールが対応している3.1がおすすめです。3.0から3.1に移るときは、nullable: true の書き方などが変わる点に注意します。

よくある質問

Q. SwaggerとOpenAPIの違いは何ですか? A. 仕様の名前は、Swagger 2.0の後に「OpenAPI」に変わりました。現在「Swagger」は、Swagger UIやSwagger Editorなどのツールの名前として使われています。

Q. YAMLとJSONのどちらで書けばいいですか? A. どちらでも同じ内容を表せます。人が書いて読むならYAMLの方が短く、読みやすいため、よく使われています。

Q. AIに仕様書を書かせてもいいですか? A. 下書きを作るのに向いています。ただし、リンターで検査し、業務のルール(必須の項目、値の範囲)が正しいかは人がレビューします。

まとめ

  • OpenAPIは、REST APIの仕様をYAMLやJSONで書く標準の形式
  • 基本は paths(エンドポイント) と components(使い回す部品)、$ref で参照する
  • 制約(必須・範囲・形式)と例まで書くと、仕様書だけで入力のルールがわかる
  • 認証は securitySchemes、エラーは RFC 9457の形式に揃える
  • リンターをCIで実行し、仕様書の間違いをマージ前に見つける
  • 画面とAPIを並行して作るなら、設計ファーストがおすすめ

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「OpenAPIの書き方|YAMLのテンプレートとチームで使う運用」

株式会社RJCでは、チームで気持ちよく開発するための設計の工夫を、プロジェクトの中で仲間と磨いています。こうした知識を共有しながら、日々学び合っています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?