Skip to content

エラーハンドリング

エラーレスポンス形式

すべてのAPIエラーは、適切なHTTPステータスコードと一貫したJSON構造に従います:

json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description of what went wrong"
  }
}

code フィールドは安定したマシンリーダブルな識別子で、エラーハンドリングロジックで使用できます。message フィールドは追加のコンテキストを提供し、同じエラーコードでも発生ごとに異なる場合があります。

エラーカテゴリ

認証エラー (401)

リクエストを認証できない場合に返されます。

コード説明
UNAUTHORIZEDAuthorization ヘッダーが欠落、不正、または無効なトークンを含んでいます。
KEY_EXPIREDAPIキーは有効でしたが、有効期限を過ぎています。続行するには新しいキーを作成してください。
json
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid Authorization header"
  }
}

認可エラー (403)

認証済みユーザーがリクエストされたリソースにアクセスする権限を持っていない場合に返されます。

コード説明
FORBIDDEN別のユーザーに属するリソースにアクセスまたは変更しようとしています(例:他のユーザーのAPIキーの無効化)。

未検出エラー (404)

リクエストされたリソースが存在しない場合に返されます。

コード説明
NOT_FOUNDURL内で識別されたリソース(抽出、APIキーなど)が存在しないか、削除されています。

バリデーションエラー (400)

リクエストボディまたはパラメータが無効な場合に返されます。

コード説明
VALIDATION_ERRORリクエストボディがスキーマバリデーションに失敗しました。message フィールドにどのフィールドが無効かが記述されます。
MAX_KEYS_REACHEDアクティブなAPIキーの上限10個に達しました。新しいキーを作成する前に、既存のキーを無効化してください。
json
{
  "error": {
    "code": "MAX_KEYS_REACHED",
    "message": "Maximum of 10 active API keys allowed"
  }
}

レート制限エラー (429)

使用量制限を超過した場合に返されます。

コード説明
USAGE_LIMIT_EXCEEDED月間抽出制限に達しました。プランをアップグレードするか、次の請求期間まで待ってください。
json
{
  "error": {
    "code": "USAGE_LIMIT_EXCEEDED",
    "message": "Monthly extraction limit reached (25/25). Upgrade your plan for more extractions."
  }
}

サーバーエラー (500)

サーバー側で予期しない問題が発生した場合に返されます。

コード説明
INTERNAL_ERROR予期しないサーバーエラーが発生しました。これらは自動的にログに記録され、調査されます。
EXTRACTION_FAILEDドキュメントからデータを抽出する際にAI処理パイプラインでエラーが発生しました。ドキュメントが破損しているか、読み取れないか、サポートされていない形式の可能性があります。

リトライ可能なエラー

すべてのエラーがリトライすべきとは限りません。以下に分類を示します:

コードリトライ可能アクション
INTERNAL_ERRORはい指数バックオフでリトライ
EXTRACTION_FAILEDはいリトライ -- AIが異なる結果を生成する場合があります。持続する場合はドキュメントの品質を確認
USAGE_LIMIT_EXCEEDEDいいえプランをアップグレードするか、次の請求期間まで待つ
UNAUTHORIZEDいいえ認証情報を修正
KEY_EXPIREDいいえ新しいAPIキーを作成
FORBIDDENいいえ所有していないリソースにアクセスしている
NOT_FOUNDいいえリソースが存在しない -- IDを確認
VALIDATION_ERRORいいえリクエストボディを期待されるスキーマに合わせて修正
MAX_KEYS_REACHEDいいえ新しいキーを作成する前に既存のキーを無効化

リトライ戦略

リトライ可能なエラーの場合、サーバーへの過負荷を避けるために指数バックオフを使用します。以下は再利用可能な実装です:

typescript
interface ApiResponse<T> {
  data?: T;
  error?: { code: string; message: string };
}

async function fetchWithRetry<T>(
  url: string,
  options: RequestInit,
  maxRetries = 3,
): Promise<ApiResponse<T>> {
  let lastError: Error | null = null;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      const body = await response.json();

      if (response.ok) {
        return body as ApiResponse<T>;
      }

      const errorCode = body?.error?.code;

      // サーバーエラーのみリトライ
      if (
        (errorCode === "INTERNAL_ERROR" || errorCode === "EXTRACTION_FAILED") &&
        attempt < maxRetries
      ) {
        const delayMs = 1000 * Math.pow(2, attempt); // 1s, 2s, 4s
        console.log(`Retrying in ${delayMs}ms (attempt ${attempt + 1}/${maxRetries})...`);
        await new Promise((resolve) => setTimeout(resolve, delayMs));
        continue;
      }

      // リトライ不可能なエラー -- 即座に返す
      return body as ApiResponse<T>;
    } catch (err) {
      lastError = err as Error;

      if (attempt < maxRetries) {
        const delayMs = 1000 * Math.pow(2, attempt);
        await new Promise((resolve) => setTimeout(resolve, delayMs));
        continue;
      }
    }
  }

  throw lastError ?? new Error("Max retries exceeded");
}

使用方法:

typescript
const result = await fetchWithRetry<ExtractionResult>(
  "https://api.docmap.io/v1/extractions/run",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      templateId: "tmpl_abc123",
      fileName: "invoice.pdf",
      pdfBase64: encodedPdf,
      mimeType: "application/pdf",
    }),
  },
);

if (result.error) {
  console.error(`Extraction failed: [${result.error.code}] ${result.error.message}`);
} else {
  console.log("Extracted data:", result.data);
}

ベストプラクティス

  • まずHTTPステータスコードを確認する。 2xx ステータスは成功を意味し、それ以外はエラーです。ステータスを確認せずにレスポンスボディに data フィールドがあると想定しないでください。

  • code フィールドでエラーボディを解析する。 制御フローでは message ではなく code を使用してください。エラーメッセージは時間とともに変わる可能性がありますが、エラーコードは安定しています。

  • 特定のエラーコードを処理する。 USAGE_LIMIT_EXCEEDEDKEY_EXPIRED などの既知のコードに分岐して、ユーザーへのターゲットメッセージの表示や特定のワークフローのトリガーを行います。

  • 不明なエラーをログに記録する。 明示的に処理していないエラーコードに遭遇した場合、デバッグのために完全なレスポンス(ステータスコード、エラーコード、メッセージ)をログに記録してください。

  • 4xxエラーをリトライしない。 認証、認可、バリデーション、未検出エラーは自然に解決されません。リトライする前に根本的な問題を修正してください。

  • リトライ回数に制限を設ける。 無限にリトライしないでください。指数バックオフ(1秒、2秒、4秒)での3回のリトライは、サーバーエラーに対する妥当なデフォルトです。

DocMap API ドキュメント