「Web API: The Good Parts」は、O’Reilly Japanから出版されている水野秀信氏による名著であり、API設計に携わるエンジニアにとってのバイブル的な存在です。
この本は、単に「動くAPI」を作るのではなく、「使いやすく、理解しやすく、堅牢なAPI(Beautiful Web API)」を設計するための思想と実践的なテクニックが凝縮されています。
以下に、エンジニアの視点で再構成した詳細な要約を提供します。
はじめに:なぜ「良いAPI」が必要なのか
Web APIは、単なるデータ通信のパイプではありません。それは開発者(人間)が利用するインターフェースです。
著者は、Web APIの重要性が増している現代において、以下の要素が不可欠であると説いています。
美しいAPIの条件
- 使いやすい
- 変更しやすい
- 頑丈である
- 恥ずかしくない(標準に準拠している)
本要約では、これらの条件を満たすための具体的な設計論を章ごとに紐解いていきます。
第1章 Web APIとは何か
この章では、Web APIの役割と重要性の変遷について解説されています。特に重要なのは、「URL(URI)こそがAPIのインターフェースである」という認識を持つことです。
Web APIの美学
APIを利用するのはプログラムですが、そのプログラムを書くのは人間です。したがって、「設計者の意図が直感的に伝わる設計」が求められます。
- REST (Representational State Transfer): Webのアーキテクチャスタイル。
- RPC (Remote Procedure Call): 手続き呼び出し型。
- GraphQL: 近年台頭してきたクエリ言語(本書執筆時点以降のトレンドですが、比較対象として重要)。
比較:APIアーキテクチャの選定
| 特徴 | RESTful API | RPC (gRPCなど) | GraphQL |
| リソース指向 | ◎ (URIでリソースを表現) | △ (機能・アクション指向) | ◎ (グラフ構造) |
| キャッシュ | ◎ (HTTPキャッシュが効く) | × (独自実装が必要) | △ (クライアント側で工夫が必要) |
| ペイロード | JSON/XML (大きくなりがち) | Protocol Buffers (軽量) | クエリで指定可能 (最適化) |
| いつ選ぶべきか | 標準的なWebサービス、公開API | マイクロサービス間通信、低遅延 | クライアントの要求が多岐にわたる場合 |
第2章 エンドポイントの設計とリクエストの形式
API設計において最も議論になり、かつセンスが問われるのが「URI設計」です。
1. URIは短く、入力しやすく
良いURIは、それを見ただけで何ができるかが推測できる。
- 悪い例:
/api/get-user-data-list.php?type=active(実装の詳細が見えている) - 良い例:
/users?status=active(リソースが明確)
2. 名詞を使用する(動詞はHTTPメソッドで)
URIには動詞を含めず、名詞(リソース名)を使います。操作の内容はHTTPメソッドで表現します。
graph LR
Client[クライアント]
Server[サーバー]
Client -- "GET /users (取得)" --> Server
Client -- "POST /users (新規作成)" --> Server
Client -- "PUT /users/1 (更新)" --> Server
Client -- "DELETE /users/1 (削除)" --> Server
style Client fill:#f9f,stroke:#333,stroke-width:2px
style Server fill:#bbf,stroke:#333,stroke-width:2px3. 単数形か複数形か?
この議論に対し、本書では「すべて複数形にする」ことを推奨しています。
/users(コレクション)/users/123(特定のリソース)- 理由:
/user/123と/usersが混在すると、利用者が迷うため、統一性が重要です。
4. クエリパラメータとパスペラメータの使い分け
| 種類 | 形式 | 用途 | 具体例 |
| パス | /users/123 | リソースを一意に識別する | 特定のユーザーID |
| クエリ | /users?page=2 | 絞り込み、ページネーション、並び替え | 2ページ目、検索条件 |
第3章 レスポンスデータの設計
リクエストに対する「答え」であるレスポンスの設計は、開発者体験(DX)に直結します。
1. JSON一択の時代
XMLなどは特殊な要件がない限り避け、JSONを採用します。
2. データ構造のフラット化 vs エンベロープ(封筒)
データを meta 情報などで包むべきかどうか。
- エンベロープあり:
{
"header": { "status": "success" },
"response": { "id": 1, "name": "Gemini" }
}- エンベロープなし(推奨):
{
"id": 1,
"name": "Gemini"
}HTTPステータスコードやヘッダーがあるため、レスポンスボディで二重にメタ情報を送る必要性は薄れています。シンプルさを優先しましょう。
3. エラー表現の標準化
エンジニアが最も苦しむのが「不明瞭なエラー」です。以下の要素を必ず含めるべきです。
- 開発者向けメッセージ: 具体的なデバッグヒント。
- ユーザー向けメッセージ: UIに表示可能な文言。
- エラーコード: アプリケーション固有のコード。
推奨されるエラーフォーマット:
JSON
{
"code": 1024,
"message": "Validation Failed",
"errors": [
{
"field": "email",
"message": "Invalid email format"
}
]
}第4章 HTTPの仕様を最大限利用する
多くのAPI開発者が「とりあえずJSONが返ればいい」と考えがちですが、著者は「HTTPプロトコル自体が持っている機能を正しく使うこと」こそが良いAPI(The Good Parts)への近道だと説いています。
1. ステータスコードの使い分け
ステータスコードは、サーバーからクライアントへの「最初のメッセージ」です。レスポンスボディをパースしなくても、クライアントが次に取るべき行動(リトライ、認証画面への遷移、エラー表示など)を決定できるようにする必要があります。
| クラス | 意味 | 代表的なコードと使用例 |
| 2xx | 成功 | 200 OK: 一般的な成功 201 Created: リソース作成成功( LocationヘッダでURLを返す)204 No Content: 削除成功時など、返すデータがない場合 |
| 3xx | 転送 | 304 Not Modified: キャッシュ有効(後述) 301 Moved Permanently: APIのエンドポイント変更 |
| 4xx | クライアントエラー | 400 Bad Request: パラメータ不備 401 Unauthorized: 認証が必要(トークンなし/無効) 403 Forbidden: 禁止(権限不足) 429 Too Many Requests: レートリミット超過 |
| 5xx | サーバーエラー | 500 Internal Server Error: サーバー側のバグ、障害 503 Service Unavailable: メンテナンス中 |
2. HTTPキャッシュの技術
APIのパフォーマンスとスケーラビリティを劇的に向上させるのがキャッシュです。著者は2つのモデルを使い分けるよう推奨しています。
A. Expiration Model(期限切れモデル)
「この日時まではサーバーに問い合わせずにキャッシュを使ってよい」という指定です。
- ヘッダー:
Cache-Control: max-age=3600 - 効果: サーバーへのアクセスが完全に発生しないため、最も高速。
- 用途: 更新頻度が低いマスタデータ、過去の履歴データなど。
B. Validation Model(検証モデル)
「キャッシュを持っているが、まだ有効かサーバーに確認する」モデルです。
- ヘッダー:
Last-Modified(日付) またはETag(データのハッシュ値) - 動作: クライアントは
If-Modified-SinceやIf-None-Matchヘッダを付けてリクエストします。サーバーはデータに変更がなければ304 Not Modifiedを返し、ボディ(実データ)の転送を省略します。 - 用途: 常に最新が必要だが、変更がない場合の通信量を減らしたい場合(タイムライン、ユーザー情報など)。
sequenceDiagram
participant Client
participant Server
Note over Client, Server: Validation Model (ETag) の流れ
Client->>Server: GET /users/123
Server-->>Client: 200 OK<br/>ETag: "hash_v1"
Note right of Client: クライアントが ETag を保存
Client->>Server: GET /users/123<br/>If-None-Match: "hash_v1"
alt データ変更なし
Server-->>Client: 304 Not Modified<br/>(ボディなし)
else データ変更あり
Server-->>Client: 200 OK<br/>ETag: "hash_v2"<br/>{ "id": 123, ... }
end3. メディアタイプの指定
Content-Type ヘッダは必須です。JSONを返す場合は必ず application/json を指定します。クライアントが何を求めているかは Accept ヘッダで判断します。
第5章 設計変更をしやすいWeb APIを作る
Web APIは一度公開すると、クライアントアプリ(iOS, Android, 他社システム)が存在するため、簡単に変更できません。この章では、「変更が発生することを前提とした設計」について解説されています。
1. APIのバージョニング戦略
APIに破壊的な変更(後方互換性のない変更)を加える場合、バージョン管理が必須となります。本書では以下の3パターンを比較しています。
| 方式 | URL例 / 方法 | メリット | デメリット | 本書の推奨 |
| URIパス | /v1/users | ブラウザで確認しやすい。 どのバージョンを使っているか一目瞭然。 | URIは「リソース」を表すべきというRESTの原則的には微妙。 | ◎ 推奨 (実用性重視) |
| クエリパラメータ | /users?ver=1 | 実装が容易。デフォルト値を設定しやすい。 | クエリパラメータは本来「絞り込み」などに使うべき。 | △ |
| メディアタイプ | Accept: application/vnd.company.v1+json | URIが汚れず、最もRESTful。 | テストや確認が面倒(ヘッダ操作が必要)。 | 〇 |
著者の見解:
学術的な正しさよりも「開発者のわかりやすさ」を優先し、URIパスにバージョンを含める方法(/v1/)が最も現場に適しているとしています。
2. バージョンのライフサイクル管理
新しいバージョンを作った後、古いバージョンをいつ、どのように停止するか(Sunset)も設計の一部です。
- セキュリティポリシー: 古いバージョンは「セキュリティ修正のみ行う」などのポリシーを明確にする。
- Sunsetヘッダー: 近い将来廃止されるAPIに対し、
Sunsetヘッダで廃止日時を予告する(RFC 8594)。
3. 変更に強いレスポンス設計
- データ型を変えない:
idが数値だったり文字列だったりしないようにする。 - 不要な項目を削除しない: 使わなくなったフィールドも、いきなり削除せず、常に
nullや固定値を返して互換性を保つ。
第6章 堅牢なWeb APIを作る
この章では、APIを公開する際に避けて通れない「セキュリティ」と「安定性」について、攻撃者の視点も交えて解説されています。
1. Web API特有のセキュリティ対策
Webページと異なり、APIはプログラムから直接叩かれるため、特有の配慮が必要です。
- HTTPSの強制:もはや選択肢ではなく必須です。中間者攻撃(Man-in-the-middle attack)を防ぎ、トークンや個人情報を守ります。
- XSS (クロスサイトスクリプティング) 対策:APIが返すJSONの中に、攻撃者が悪意あるスクリプト (
<script>...) - JSONハイジャック:古いブラウザの脆弱性を突き、悪意のあるサイトが他サイトのJSONデータを読み取ってしまう攻撃。
- 対策: JSONの先頭に
while(1);などの無限ループコードを付加し、スクリプトとして実行された場合にクラッシュさせる(Googleなどが採用していた手法)。現代ではCORS設定とモダンブラウザの使用でほぼ防げます。
- 対策: JSONの先頭に
- CSRF (クロスサイトリクエストフォージェリ):認証にCookieを使用している場合、攻撃者の罠サイト経由でAPIを勝手に叩かれるリスクがあります。
- 対策:
Authorizationヘッダ(Bearerトークン)を使用する方式であれば、Cookieを使わないためCSRFの影響を受けにくくなります。
- 対策:
2. セキュリティヘッダー一覧
サーバーサイドエンジニアは、以下のヘッダーをミドルウェア等で自動付与するよう設定すべきです。
| ヘッダー名 | 設定値の例 | 目的 |
| X-Content-Type-Options | nosniff | IEなどがコンテンツの中身を見て勝手にファイルタイプを解釈するのを防ぐ。 |
| X-Frame-Options | DENY | iframe内での表示を禁止し、クリックジャッキングを防ぐ。 |
| Strict-Transport-Security | max-age=31536000 | HTTPS接続を強制する (HSTS)。 |
| Content-Security-Policy | default-src 'none' | APIの場合、リソースの読み込みを制限してXSSのリスクを下げる。 |
3. レートリミット (Rate Limiting)
DoS攻撃やスクレイピングによる過負荷を防ぐため、APIには利用制限を設けます。
- 単位: 「1分間に60リクエスト」「1日10000リクエスト」など。
- 識別: ユーザーIDごと、IPアドレスごと、APIキーごと。
- 通知: 制限を超えた場合は
429 Too Many Requestsを返し、いつ解除されるか(RateLimit-Reset)をヘッダで伝えます。
flowchart LR
Request[リクエスト受信] --> Check{制限内か?}
Check -- Yes --> Process[処理実行]
Process --> Decrement[残数-1]
Decrement --> Response[200 OK + 残数ヘッダ]
Check -- No --> Block[遮断]
Block --> ErrorResponse[429 Too Many Requests]アクションプラン:明日から実践できる5つのステップ
この要約を読んだあなたが、明日から現場で活かせる具体的なアクションプランです。
- [現状分析] エンドポイントの棚卸しをする
- 現在のAPIのURIを見てください。動詞が入っていませんか? (
/getUserなど)。まずはそれをリストアップし、RESTfulなURI (GET /users) にマッピングする計画を立てましょう。
- 現在のAPIのURIを見てください。動詞が入っていませんか? (
- [ルール策定] ステータスコードの厳格化
- エラー時にすべて
200 OKを返していませんか? バリデーションエラーなら400、認証エラーなら401を返すように、フレームワークの例外ハンドリングを修正しましょう。
- エラー時にすべて
- [標準化] エラーレスポンスの統一
- 成功時はJSON、失敗時はHTML(Webサーバーのデフォルト)が返ってきていませんか? どのようなエラーでも必ず決まった形式のJSONが返るようにミドルウェアを設定しましょう。
- [パフォーマンス] Cache-Controlを導入する
- 更新頻度の低いリソース(マスタデータなど)に対し、
Cache-Control: max-age=3600などのヘッダーを付与するだけで、サーバー負荷とネットワーク遅延を劇的に改善できます。
- 更新頻度の低いリソース(マスタデータなど)に対し、
- [文書化] OpenAPI (Swagger) を導入する
- 「美しいAPI」はドキュメントも美しいものです。コードからAPIドキュメントを自動生成する仕組みを導入し、クライアント開発者とのコミュニケーションコストを下げましょう。
書籍情報
タイトル: Web API: The Good Parts
著者: 水野 秀信
出版社: オライリー・ジャパン
最後に
API設計は「おもてなし」の心です。利用する開発者がストレスなく、直感的に使えるAPIこそが、優れたプロダクトの基盤となります。この要約があなたのエンジニアリングの一助となれば幸いです。

コメント