- ソフトウェアエンジニアリングにおいてAPIは中核的なツールであり、優れたAPIは退屈なくらい親しみやすくシンプルであることが望ましい特徴
- APIは一度公開すると変更が難しいため、ユーザー環境を壊さない原則(WE DO NOT BREAK USERSPACE) が重要
- やむを得ず変更する場合は バージョン管理(versioning) が必要だが、これは複雑さと保守コストを大きく増加させる必要悪
- APIの品質は結局 プロダクト自体の価値 に依存しており、設計の悪いプロダクトでは良いAPIを作るのが難しい
- 安定性と拡張性のために APIキーベース認証、冪等性(idempotency)、レートリミット、カーソルベースのページネーション などを考慮すべき
序論: API設計の重要性と文脈
- 現代のソフトウェアエンジニアの主要業務の一つは APIと相互作用 すること
- 著者自身もREST、GraphQL、コマンドラインツールなど、さまざまな形の公開および社内向けAPIを設計・実装・活用してきた経験を持つ
- 既存のAPI設計アドバイスは、複雑な概念(RESTの定義、HATEOASなど)に執着する傾向がある
- 本稿は実体験に基づいて 実用的なAPI設計原則 を整理したもの
親しみやすさと柔軟性のバランス: 良いAPIの第一条件
- 良いAPIは「平凡で退屈な」API、つまり既存のAPIと使い方が似ているべき
- ユーザーは APIそのものより自分の目的達成に集中 しているため、参入障壁の低い設計が必要
- 一度公開されたAPIは 変更が非常に難しく、最初の設計段階で慎重さが求められる
- 開発者はできるだけ簡潔なAPIを望む一方で、長期的な柔軟性を残すための悩みが常につきまとう
- 結果として、親しみやすさと長期的柔軟性のバランス が核心的な課題
ユーザー空間を決して壊さない(WE DO NOT BREAK USERSPACE)
- 既存のレスポンス構造に フィールドを追加 する変更は、ほとんどの場合問題ない
- しかし フィールドの削除、型や構造の変更 は、すべての利用側コードを壊す結果を招く
- APIの保守者には、既存ユーザーのソフトウェアを意図的に壊さない 責任 がある
- HTTPの
referer ヘッダーのスペルミスすら修正しない理由は、ユーザー空間を保全する文化 にある
APIを壊さずに変更する: バージョン管理戦略
- 本当に必要な場合にのみ APIへの破壊的変更 を認め、その際は バージョン管理 が正解
- 旧バージョンと新バージョンを 同時に運用しながら段階的な移行 を促すべき
- バージョン識別子はURL(
/v1/)やヘッダーなど、さまざまな方式で利用でき、ユーザーは各自の速度で移行できる
- バージョン管理には 莫大な保守コスト(エンドポイント増加、テスト、サポート)と ユーザーの混乱 という欠点がある
- Stripeのように内部に変換レイヤーを置いても、根本的な複雑さは避けられない
- APIのバージョン管理導入は最終手段 であるべき
APIの成功要因は全面的にプロダクト価値にかかっている
- APIは本質的に 実際のビジネスプロダクトのインターフェースにすぎない
- OpenAIやTwilioのAPIでも、結局ユーザーが求めていたのは APIが提供する機能そのもの
- 価値あるプロダクトなら、APIが使いにくくても利用される
- API品質は「マージン」の特性であり、本質的な競争力が近いときにだけ選択要因になる
- 一方で、そもそもAPIが存在しないプロダクトは技術ユーザーにとって大きな障壁になる
プロダクト設計が悪ければAPIも良くなりえない
- 技術的に完成度の高いAPI があっても、市場性のないプロダクト なら意味がない
- さらに重要なのは、基本的なリソース構造が非論理的または非効率的であれば、それはAPIにも現れる こと
- たとえばコメントをリンクドリストで保存するシステムでは、RESTfulな設計さえ自然に組みにくくなる
- UIでは隠せる技術的問題も、APIではすべて露出し、ユーザーにシステム理解を不必要に強いることになる
認証(Authentication)とユーザーの多様性
- 長寿命のAPIキーベース認証 を必ずサポートすべき
- OAuthのようなより安全な方式を追加でサポートするとしても、APIキーの 参入障壁は圧倒的に低い
- APIの利用者はエンジニアだけでなく、非開発者(営業、企画、学生、趣味開発者など)も多い
- 難しい、または複雑な認証要件(OAuthなど)は 非専門ユーザーにとって障壁 になる
冪等性(Idempotency)とリトライ処理
- アクション系リクエスト(例: 決済、状態変更など)は、失敗時の リトライ(retry) に対する安全性が重要
- 冪等性とは、同じリクエストを複数回送っても結果が一度しか処理されないことを保証 すること
- 標準的な方法は「冪等性キー」をパラメータまたはヘッダーで渡して重複処理を防ぐこと
- 冪等性キーの保存にはRedisなどの 単純なキー/バリューストア で十分であり、多くの場合は定期的な有効期限切れを適用しても問題ない
- 読み取り/削除リクエスト(REST方式)には通常必要ない
APIの安全性とレート制限(Rate limiting)
- コード経由のAPIリクエストはユーザー操作よりはるかに高速で発生 しうる
- 何気なく公開した1つのAPIが、意図しない形(例: 大規模チャットシステム)で利用されることもある
- レート制限(ratelimit)は必須 であり、高コストな処理にはより厳しく適用すべき
- 特定顧客に対する一時的なAPI無効化(killswitch)も選択肢として考慮すべき
- レスポンスヘッダー(
X-Limit-Remaining, Retry-After など)でレート制限情報を案内すべき
ページング(Pagination)戦略
- 大規模データセット(例: 数百万件のチケット)を効率的に返すには ページングが必須
- オフセットベース(Offset-based)のページングは簡単だが、大量データでは次第に遅くなる
- カーソルベース(Cursor-based)のページング は、クエリ性能を落とさず非常に大きなデータセットにも有効
- カーソルベースは実装と利用がやや難しいが、長期的には不可欠な変化になる可能性が高い
- レスポンスに
next_page フィールドなどを含め、次のリクエスト用カーソルを明確に案内するのが賢明
選択的フィールドとGraphQLについての見解
- コストが高い、または遅いフィールドはデフォルトのレスポンスから除外し、必要時のみ選択的に追加 すべき
includes パラメータなどで関連データを含められる
- GraphQLにはデータ構造の柔軟性という利点があるが、非開発者のアクセス性低下、キャッシュ/エッジケースの複雑化、バックエンド実装難易度 などの問題がある
- 実務経験上、GraphQLの導入は 本当に必要な場合に限る のが適切
内部向けAPIの特徴
- 社内APIは外部向けAPI(公開API)とは多くの条件が異なる
- 利用者の大半は 専門のソフトウェアエンジニア であるため、より複雑な認証や破壊的変更も可能
- それでも、冪等性、事故防止、運用負荷最小化 のための設計原則は有効
要約
- APIは変更しにくく、使うのは簡単であるべき という特性を持つ
- ユーザー空間を壊さないこと がAPI保守者の最も重要な義務
- APIのバージョン管理はコストが大きいため最終手段 としてのみ使うべき
- 最終的に APIの品質はプロダクトの本質的価値に左右される
- 設計の悪いプロダクトはAPIレベルで補っても限界が大きい
- シンプルな認証方式のサポート、必須アクションリクエストへの 冪等性、そして レート制限/ページングなどの安定化策 が重要
- 内部APIは用途と対象に応じて戦略が異なるが、設計の慎重さは依然として必要
- REST、JSONなどのフォーマットやOpenAPIなどは本質的な論点ではない。明確なドキュメント化のほうが重要
まだコメントはありません。