Address Search API

エラーとRate Limit

requestの修正が必要なerrorと、安全に再試行できる一時errorを分けて扱います。

PostcodeJP Docs
ドキュメントメニュー

HTTP statusと対応

StatusMeaningAction
400filter、field、sort、cursorなどが無効requestを修正。自動retryしない
401API Keyが無効または不足認証情報を確認。自動retryしない
403Referer/IP/権限/利用範囲により拒否API Keyの制限と契約を確認
404routeまたはresourceが存在しないpathを確認
405HTTP methodが不正GETへ修正
406要求したresponse formatを返せないAcceptを確認
429API Keyの利用上限を超過reset情報に従って待機
500内部error上限付きbackoffで再試行
503一時的に利用できない上限付きbackoffで再試行

検索結果が0件の場合

条件に一致するデータがない場合もrequestは成功です。404ではなく、HTTP 200と空のdataが返ります。

Zero results
{
  "data": [],
  "size": 0,
  "limit": 10,
  "hasNext": false,
  "hasPrev": false,
  "version": "dataset-version"
}

Application error schema

Search application error
{
  "httpStatusCode": 400,
  "code": "invalidParameter",
  "message": "...",
  "validationErrors": [
    {
      "message": "...",
      "paramName": "filter",
      "invalidValue": "..."
    }
  ]
}

401、403、429のbodyは、このapplication error schemaと同じとは限りません。clientはまずHTTP statusを判定してください。human-readable messageの完全一致に依存しないでください。

Rate limit headers

利用できるwindowはAPI Keyのplan設定により異なります。header名はcase-insensitiveです。

HeaderMeaningUnit
RateLimit-Limit最も制約の強いwindowの上限request count
RateLimit-Remaining同windowの残数request count
RateLimit-Reset同windowがresetするまでseconds
Retry-After429後、再試行まで待つ時間seconds
X-RateLimit-Limit-Second1秒windowの上限(設定時)request count
X-RateLimit-Remaining-Second1秒windowの残数(設定時)request count
X-RateLimit-Limit-Day1日windowの上限(設定時)request count
X-RateLimit-Remaining-Day1日windowの残数(設定時)request count
429では連続送信しない

429を受けたらrequestを止め、返されたreset情報に従ってから再試行してください。

Bounded retry

429と一時的な5xxだけを対象に、試行回数に上限を設けたexponential backoffとjitterを使用します。400、401、403はrequestまたは設定を修正するまでretryしません。

Retry example
async function requestWithBackoff(request, maxAttempts = 3) {
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
    const response = await request();
    if (response.ok) return response;

    const retryable = response.status === 429 || response.status >= 500;
    if (!retryable || attempt === maxAttempts - 1) return response;

    const retryAfter = Number(response.headers.get("Retry-After"));
    const baseMs = Number.isFinite(retryAfter)
      ? retryAfter * 1000
      : Math.min(1000 * 2 ** attempt, 30000);
    const jitterMs = Math.random() * 250;
    await new Promise((resolve) => setTimeout(resolve, baseMs + jitterMs));
  }
}