冪等リクエスト
冪等リクエストを使用して二重決済を防止する方法
ネットワークエラーやタイムアウトで二重決済など、同じリクエストが複数回実行されることを防ぐには冪等リクエストを使用します。
冪等リクエストを使用する際は、UUID やタイムスタンプ、ランダム文字列などの一意なキーを生成し、リトライが必要になった場合に備えてサーバー側に保存します。 エラー発生時のリトライ処理など、同じリクエストを意図的に再試行する場合のみ同じ冪等キーを再利用します。
冪等リクエストの基本
// 冪等キーを生成(UUIDなど一意な値を使用)
function generateIdempotencyKey() {
return crypto.randomUUID();
}
const idempotencyKey = generateIdempotencyKey();
const response = await fetch('https://api.pay.jp/v2/payment_flows', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey // 冪等キーを指定
},
body: JSON.stringify({
amount: 1000,
currency: 'jpy'
})
});冪等キーの要件
| 項目 | 要件 |
|---|---|
| 最大文字数 | 255文字 |
| 使用可能文字 | 英数字(a-z, A-Z, 0-9)、ハイフン(-)、アンダースコア(_)のみ |
| 対応HTTPメソッド | POST, PUT, PATCH |
冪等リクエストエラーの処理
冪等リクエストに関連するエラーコードは以下のとおりです。
| エラーコード | ステータス | 説明 | 対応方針 |
|---|---|---|---|
invalid_idempotency_key | 400 | 冪等キーのフォーマットが不正 | キーの形式を確認し修正 |
idempotency_conflict | 409 | 同じキーで異なるパラメータのリクエストが送信された | 新しいキーで再実行 |
idempotency_timeout | 409 | 元のリクエストの完了待ちがタイムアウト | 同じキーで再試行 |
idempotency_infrastructure_error | 503 | 冪等チェック機能が一時的に利用不可 | リトライ可能 |
async function makeIdempotentRequest(params) {
const idempotencyKey = generateIdempotencyKey();
const response = await fetch('https://api.pay.jp/v2/payment_flows', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey
},
body: JSON.stringify(params)
});
if (response.ok) {
return await response.json();
}
const error = await response.json();
if (error.code === 'idempotency_conflict') {
console.error('同じ冪等キーで異なるリクエストが送信されました');
// この関数内で自動リトライは行わず、呼び出し側での対処(確認・再実行など)に委ねる
throw error;
}
if (error.code === 'idempotency_timeout') {
console.warn('元のリクエストの完了待ちがタイムアウトしました');
// 同じ冪等キーで再試行するか、ユーザーに確認してから新しいキーで再実行するかは、
// ビジネスロジックに応じて呼び出し側で制御してください
}
if (error.code === 'idempotency_infrastructure_error') {
console.warn('冪等チェック機能が一時的に利用不可です');
// リトライ可能。待機時間を徐々に長くしながら再試行
}
throw error;
}