はじめに
APIを実装していると、「同じリクエストが複数回送られてきたらどうなるのか?」と疑問に思ったことはありませんか?
特に、決済処理やユーザー登録のような失敗が許されないAPIでは、この問題は非常に重要です。
本記事では、APIに冪等性を追加する方法について、概念の整理からデータベース設計、実際のAPIの流れまでを段階的に解説していきます。
冪等性とは何か
冪等性(Idempotency)の定義
冪等性とは、「同じ操作を何度実行しても、結果が変わらない性質」を指します。
これは数学や関数型プログラミング由来の概念ですが、Web APIの設計においても非常に重要です。
つまり、冪等なAPIとは以下を満たすAPIです。
- 同一のリクエストを複数回送信しても
- サーバー側の最終的な状態やレスポンスが変わらない
この性質について、解説していきます。
なぜ冪等性が重要なのか
API通信では、以下のようなことが日常的に発生します。
- ネットワークタイムアウト
- クライアント側のリトライ処理
- ロードバランサやプロキシによる再送
例えば、決済APIで以下の流れを想像してみてください。
- クライアントが「支払いリクエスト」を送信
- サーバー側では決済が完了
- しかし、レスポンスが返る前に通信が切断
- クライアントが「失敗した」と判断して再送
このとき冪等性がなければ、二重決済が発生してしまいます。
つまり、冪等性は「安全に再試行するための仕組み」を提供します。
どんなときに冪等性が必要か
特に以下のようなAPIでは、冪等性が強く求められます。
- 決済・課金API
- ユーザー登録・アカウント作成API
- 注文作成API
- 外部サービス連携API(Webhook受信など)
つまり、副作用を伴うAPIでは、冪等性の考慮がほぼ必須です。
冪等性APIの基本的なアプローチ
冪等キー(Idempotency Key)を使う方法
Web APIで一般的なのは、「冪等キー」を用いた方法です。
- クライアントが一意なキーを生成
- リクエストヘッダーやボディに含めて送信
- サーバー側でそのキーを元に処理結果を管理
つまり、同じ冪等キーを持つリクエストは、常に同じ結果を返すことを保証します。
APIの振る舞い(概要)
冪等キーを使ったAPIは、以下のように振る舞います。
- 初回リクエスト
- 通常通り処理を実行
- 結果を冪等キーと紐づけて保存
- 2回目以降の同一キーのリクエスト
- 処理は実行しない
- 保存済みの結果をそのまま返却
つまり、処理の重複実行を防止できます。
データベース設計
冪等性を実現するためのテーブル設計
冪等性を実装するためには、データベースで「処理済みかどうか」を管理する必要があります。
一例として、以下のようなテーブルを用意します。
| カラム名 | 型 | 説明 |
|---|---|---|
| id | bigint | 主キー |
| idempotency_key | varchar | 冪等キー(ユニーク) |
| request_hash | varchar | リクエスト内容のハッシュ |
| response_body | json | レスポンス内容 |
| status | varchar | 処理ステータス |
| created_at | timestamp | 作成日時 |
-
idempotency_keyには UNIQUE制約 を付けます -
request_hashを保存することで、異なる内容の再送を検知可能です -
response_bodyを保存しておくことで、再送時に同じレスポンスを返せます
同じ冪等キーで異なるリクエスト内容が送られてきた場合は、エラーとして扱う設計が一般的です。
トランザクションと排他制御
冪等性を正しく保証するためには、以下が重要です。
- 冪等キーの存在確認
- 新規レコードの作成
- 実際のビジネス処理
これらは必ずトランザクション内で実行します。
そうしないと、同時リクエストによる競合が発生する可能性があります。
冪等性APIの処理フロー
シーケンス図で理解する
以下は、冪等キーを使ったAPIの一般的な処理フローです。
- 初回リクエストのみ、実際の処理を実行します
- 2回目以降は、DBに保存された結果を返します
- これにより、クライアントは安全にリトライが可能です
まとめ
- 冪等性とは、同じ操作を何度実行しても結果が変わらない性質です
- ネットワークやリトライを前提とするAPIでは、冪等性が重要です
- 冪等キーを用いることで、安全な再送処理を実現できます
- データベース設計とトランザクション管理が、冪等性の要となります
個人的には、冪等性を意識するようになってから、API設計に対する安心感がかなり増した気がします。
「とりあえずPOSTだから危険」という状態から一歩進める考え方だと思います。