- 技術 💻
OpenAPIの書き方|YAMLのテンプレートとチームで使う運用
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期連続の黒字決算。