sano11o1

WebAPIの冪等性についておさらい

公開日:

https://brandur.org/idempotency-keys を読んでいて以下の疑問が湧いた。

  • そもそもWebAPIにおける冪等性の正確な定義はなんでしたっけ?
  • どのような時に冪等性が求められるか?

以前考えた記憶があるが忘れているので文章に残しておく。

冪等性の正確な定義

https://developer.mozilla.org/ja/docs/Glossary/Idempotent では以下の通り

ある HTTP メソッドがべき等であるとは、サーバーが同じ状況にあるとき、特定のリクエストに対して何回でも続けて同じ効果が起こることをいいます。このことは、べき等なメソッドでは (統計を取る際のことを除いて) 副作用が生じるはずではないと言うこともできます 。

「何回でも続けて同じ効果が起こる」= 同じリクエストを複数回行っても効果が起きるのは1度だけであるということ。
ここでいう効果とは、データベースに保存しているレコードの状態の変化やサーバーがリクエストする別のAPIによる変化が含まれる。
ちなみにレスポンスコードは変わっても良いとのこと。

べき等であるためには、サーバーにおける裏側の実際の状態だけが考慮されるので、返される状態コードはリクエストごとに異なる場合があります。

このAPIが冪等か?を考えるには、そのAPIを同じリクエストで複数回叩いた時の効果に注目する。

ここからは自分の考えだが、「同じリクエストを複数回行っても効果が起きるのは1度だけ」であるなら、1回は確実に効果を起こす必要があり、安全にリトライできるはずである。
もしあるAPIを1度実行した時に500が返ってきて、何度リトライしても500を返すとする。
リクエストが正常であるのに、500を返すならこのAPIは一度も効果を発揮していないことになるため、冪等の厳密な定義からは外れる。
とはいえ、現実問題としてサーバーに保存されているレコードの状態や、依存する外部のAPIの状態によっては一度も効果を発揮しないAPIも存在する。
できる限り安全にリトライ可能なAPIを構築したい。

冪等性を担保した方が良いパターン

同じリクエストを複数回行っても効果が起きるのは1度だけにしたい具体的なパターンを挙げる。

SNSのいいね機能

いいねをつけられるのは投稿, ユーザー単位で1つまでであるため。
複数回リクエストを送った時、1ユーザーが複数のいいねを同じ投稿に作成できてしまうのはまずい。

決済を実行するAPI

このAPIを実行すると銀行口座から引き落とし決済を実行する。
リクエストに成功、決済が完了したが、クライアント側のネットワークの不調によりリトライすることになる。
リトライのリクエストは成功した。この時引き落とし(APIの効果)は何回実行されるだろうか?
冪等性が担保されていれば1回。されていなければリクエスト回数分の2回実行される。

冪等性を担保しなくても良いパターン

リクエスト毎にリソースを操作したい/作成しても困らない場合。
GitHubのIssuesの作成はこれに該当する。https://auth0.com/docs/api/management/v2/users/post-users
もし誤って同じ内容のIssueを2つ作成しても後から消せば大きな問題には繋がらないはず。

どのHTTPメソッドを使うか?

教科書的な回答は冪等なAPIはPUTを使うことになる。
POSTのAPIでも「同じリクエストを複数回行っても効果が起きるのは1度だけ」な実装にすることは可能である(もちろんPUTの場合も同じ実装をすることになる)
例えばAuth0にユーザーを作成するAPIのHTTPメソッドはPOSTだが、再度同じリクエストをすると409を返す。
https://auth0.com/docs/api/management/v2/users/post-users
結局のところ「同じリクエストを複数回行っても効果が起きるのは1度だけ」と制御するかは実装次第である。
APIのインタフェースから冪等であることを表現できるので、冪等なAPIにはやはりPUTを使った方が良いと考えている。

まとめ

APIの利用者のユースケース、システム全体への影響度によって冪等性を担保するべきかが決まる。
APIを設計の初期段階で冪等であるべきか?を考えていきたい。