エラーハンドリング
APIFuse のエラーレスポンスを読み、リトライすべき失敗とアップストリームサービスが拒否したリクエストを見分ける方法。
エラーハンドリング
APIFuse のすべてのエラーレスポンスは 3 つのことを伝えます: 何が起きたか(code、message)、誰がリクエストを止めたか(source)、同一リトライが成功し得るか(retryable)。HTTP ステータスコードのパターンマッチではなく、これらのフィールドを使ってください。
エラーレスポンスの形
{
"error": {
"code": "UPSTREAM_REJECTED",
"message": "The requested time slot overlaps an existing reservation.",
"retryable": false,
"source": "upstream_rule",
"fix": "Pick a slot that does not overlap the account's existing reservations.",
"requestId": "req_1a2b3c"
}
}| フィールド | 意味 |
|---|---|
code | 安定した機械可読コード。オペレーション固有のコードは各オペレーションのリファレンスページに記載されます。 |
message | 人間向けの要約。 |
retryable | false の場合、同一リトライは成功しません — リクエストを変更してください。true の場合、後でリトライすれば成功する可能性があります。 |
source | 誰がリクエストを止めたか(下記参照)。 |
fix | リクエストを成功させるために変更すべき点(判明している場合)。 |
requestId | サポートに問い合わせる際に添えてください。 |
source と retryable を省略するエラーレスポンスもあります。無い場合は下記のステータスクラスで判断してください。
プラットフォームレベルのエラー(不正な Connection ID、相手サービスへの接続タイムアウト、キャンセルされたリクエスト)は、同じフィールドをトップレベルに持つフラットな body を使います: {"error", "code", "message", "action", "retryable", "source", "request_id"}。公式 SDK は両方の形を読み取ります。
誰がリクエストを止めたか
source | 意味 | 対応 |
|---|---|---|
client | リクエスト自体の変更が必要(不正な入力、存在しない/期限切れの Connection)。 | リクエストを修正するか再接続してから呼び直してください。 |
upstream_rule | 相手サービスがリクエストを理解した上で、自身のルールにより拒否 — 売り切れ、重複する予約、アカウント状態の制限など。 | 理由をユーザーに提示するか、リクエストを変更してください。同一リトライは同じ結果になります。 |
upstream_failure | 相手サービスの障害または無応答。 | バックオフを入れてリトライしてください。 |
apifuse | APIFuse がリクエストを完了できませんでした。 | バックオフを入れてリトライし、続く場合は requestId を添えてサポートへ。 |
ステータスクラス
| ステータス | 分類 | 典型的な source |
|---|---|---|
400, 401, 404 | リクエストの変更が必要 | client |
409, 410, 422 | 相手サービスが自身のルールで拒否 | upstream_rule |
429 | レート制限 — Retry-After に従う | upstream_rule |
502, 504 | アップストリームの障害またはタイムアウト | upstream_failure |
500, 503 | APIFuse 側の障害 | apifuse |
409 は障害ではありません: 相手サービスは正常で、確定的な回答を返しています。リトライすべきエラーではなく、アプリケーションデータとして扱ってください(例:「この時間帯は既に予約済みです」と表示)。
安全なリトライ
retryable: falseのレスポンスは決して自動リトライしないでください。429はRetry-Afterの間隔後に、502/503/504は指数バックオフでリトライしてください。- 公式 TypeScript / Python SDK はこれらのルールに自動で従い、スローされたエラーで
error.retryableとerror.sourceを参照できます。
import { ApiFuseClient, ApiFuseError } from "@apifuse/sdk";
const client = new ApiFuseClient({ apiKey: process.env.APIFUSE_API_KEY! });
async function reserve(input: Record<string, unknown>) {
try {
return await client.call.invoke("catchtable", "reserve", input);
} catch (error) {
if (
error instanceof ApiFuseError &&
error.source === "upstream_rule" &&
error.retryable === false
) {
// 確定的な拒否 — リトライせずユーザーに理由を提示してください。
// (429 レート制限も source は "upstream_rule" ですが retryable の
// ため、上のガードがリトライ経路に残します。)
return { refused: true, reason: error.message, suggestion: error.fix };
}
throw error;
}
}