レスポンス形式

APIレスポンス構造の理解

mindzieAPIのレスポンス形式、ステータスコード、エラーハンドリングパターン、およびデータ構造について学び、堅牢な統合を構築しましょう。

標準レスポンス形式

すべてのmindzieAPIレスポンスは、一貫したJSONフォーマットで予測可能な構造に従っています:

成功レスポンス

{
  "data": {
    // 主なレスポンスデータ
  },
  "metadata": {
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345",
    "version": "1.0.0"
  },
  "pagination": {
    // ページネーション付きレスポンスに存在
    "currentPage": 1,
    "totalPages": 5,
    "totalItems": 100,
    "itemsPerPage": 20,
    "hasNext": true,
    "hasPrevious": false
  }
}

エラーレスポンス

{
  "error": {
    "code": "validation_failed",
    "message": "リクエストの検証に失敗しました",
    "details": {
      "field": "datasetId",
      "reason": "無効なGUID形式です"
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345"
  }
}

レスポンスタイプ

成功レスポンス

構造化されたJSONデータとメタデータを含むHTTP 2xxステータスコード。

エラーレスポンス

詳細なエラー情報を含むHTTP 4xx/5xxステータスコード。

ページネーション

大きなデータセットレスポンスのための一貫したページネーション形式。

HTTPステータスコード

成功コード (2xx)

コード ステータス 説明 用途
200 OK リクエスト成功、データが返される GETリクエスト、成功操作
201 Created リソースが正常に作成された 新規リソース作成のPOSTリクエスト
202 Accepted 非同期処理のためリクエストが受理された 長時間実行操作、キューイングされたタスク
204 No Content リクエスト成功、返すデータなし DELETEリクエスト、返却データなしの更新

クライアントエラーコード (4xx)

コード ステータス 説明 一般的な原因
400 Bad Request 無効なリクエスト形式またはパラメータ ヘッダー欠落、無効なJSON、誤ったデータ形式
401 Unauthorized 認証が必要または失敗 トークン欠落/無効、有効期限切れ認証情報
403 Forbidden 有効な認証だが権限不足 制限されたユーザーアクセス、誤ったテナント/プロジェクト
404 Not Found リクエストされたリソースが存在しない 無効なエンドポイント、存在しないリソースID
422 Unprocessable Entity 有効な形式だがビジネスロジック検証失敗 無効なビジネスルール、制約違反
429 Too Many Requests レート制限超過 一定期間内のAPI呼び出し過多

サーバーエラーコード (5xx)

コード ステータス 説明 対応策
500 Internal Server Error 予期しないサーバーエラー 指数的バックオフで再試行
502 Bad Gateway 上流サービスエラー サービス状況を確認し後で再試行
503 Service Unavailable サービス一時的に利用不可 遅延後に再試行、メンテナンス確認
504 Gateway Timeout リクエストタイムアウト タイムアウト延長、リクエスト最適化

共通レスポンスパターン

単一リソースレスポンス

{
  "actionId": "87654321-4321-4321-4321-210987654321",
  "actionType": "analyze",
  "status": "completed",
  "startTime": "2024-01-15T10:30:00Z",
  "endTime": "2024-01-15T10:32:15Z",
  "duration": 135,
  "result": {
    "outputId": "98765432-8765-4321-4321-987654321098",
    "recordsProcessed": 10000
  }
}

ページネーション付きコレクションレスポンス

{
  "actions": [
    {
      "actionId": "87654321-4321-4321-4321-210987654321",
      "actionType": "analyze",
      "status": "completed"
    },
    {
      "actionId": "11111111-2222-3333-4444-555555555555",
      "actionType": "export",
      "status": "processing"
    }
  ],
  "pagination": {
    "currentPage": 1,
    "totalPages": 5,
    "totalItems": 100,
    "itemsPerPage": 20,
    "hasNext": true,
    "hasPrevious": false,
    "links": {
      "first": "/api/Action/history?page=1&limit=20",
      "next": "/api/Action/history?page=2&limit=20",
      "last": "/api/Action/history?page=5&limit=20"
    }
  }
}

非同期操作レスポンス

{
  "operationId": "op_12345678-1234-1234-1234-123456789012",
  "status": "processing",
  "progress": {
    "percentage": 45,
    "currentStep": "data_analysis",
    "totalSteps": 5,
    "estimatedCompletion": "2024-01-15T10:35:00Z"
  },
  "trackingUrl": "/api/Execution/status/op_12345678-1234-1234-1234-123456789012",
  "message": "データセット分析を処理中です..."
}

エラーレスポンス詳細

バリデーションエラー

{
  "error": {
    "code": "validation_failed",
    "message": "リクエストの検証に失敗しました",
    "details": {
      "errors": [
        {
          "field": "datasetId",
          "code": "invalid_format",
          "message": "有効なGUIDである必要があります"
        },
        {
          "field": "parameters.timeout",
          "code": "out_of_range",
          "message": "1秒から3600秒の範囲である必要があります"
        }
      ]
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345"
  }
}

認証エラー

{
  "error": {
    "code": "invalid_token",
    "message": "提供されたアクセストークンは無効または期限切れです",
    "details": {
      "tokenType": "bearer",
      "expiresAt": "2024-01-15T09:00:00Z",
      "suggestion": "アクセストークンを更新してください"
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345"
  }
}

レート制限エラー

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "このエンドポイントのレート制限を超えました",
    "details": {
      "limit": 100,
      "remaining": 0,
      "resetTime": "2024-01-15T11:00:00Z",
      "retryAfter": 1800
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345"
  }
}

レスポンスヘッダー

標準ヘッダー

ヘッダー 説明
Content-Type レスポンス形式 application/json; charset=utf-8
X-Request-Id 一意のリクエスト識別子 req_12345678
X-Response-Time サーバー処理時間 145ms
X-API-Version 使用されたAPIバージョン 1.0.0

レート制限ヘッダー

ヘッダー 説明
X-RateLimit-Limit ウィンドウあたりの最大リクエスト数 100
X-RateLimit-Remaining ウィンドウ内の残りリクエスト数 95
X-RateLimit-Reset ウィンドウリセットのタイムスタンプ 1642251600
Retry-After 再試行までの待機秒数 3600

エラーハンドリングのベストプラクティス

JavaScriptの例

async function handleAPIResponse(response) {
  // レスポンスが正常か確認
  if (!response.ok) {
    const errorData = await response.json();

    switch (response.status) {
      case 400:
        throw new ValidationError(errorData.error.message, errorData.error.details);
      case 401:
        throw new AuthenticationError('認証に失敗しました');
      case 403:
        throw new AuthorizationError('権限が不足しています');
      case 404:
        throw new NotFoundError('リソースが見つかりません');
      case 429:
        const retryAfter = response.headers.get('Retry-After');
        throw new RateLimitError(`レート制限に達しました。${retryAfter}秒後に再試行してください`);
      case 500:
      case 502:
      case 503:
      case 504:
        throw new ServerError('サーバーエラーが発生しました。再試行してください。');
      default:
        throw new APIError(`予期しないエラー: ${response.status}`);
    }
  }

  return await response.json();
}

// リトライロジック付きの使用例
async function apiCallWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      return await handleAPIResponse(response);
    } catch (error) {
      if (error instanceof RateLimitError) {
        const retryAfter = parseInt(error.retryAfter) || Math.pow(2, attempt);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }

      if (error instanceof ServerError && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // 指数バックオフ
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      throw error;
    }
  }
}

Pythonの例

import requests
import time
from typing import Dict, Any

class APIError(Exception):
    def __init__(self, message: str, status_code: int = None, details: Dict = None):
        super().__init__(message)
        self.status_code = status_code
        self.details = details

def handle_api_response(response: requests.Response) -> Dict[str, Any]:
    """適切なエラーハンドリングを施したAPIレスポンス処理"""

    if response.ok:
        return response.json()

    try:
        error_data = response.json()
    except ValueError:
        error_data = {"error": {"message": response.text}}

    error_info = error_data.get("error", {})
    message = error_info.get("message", f"HTTP {response.status_code}")
    details = error_info.get("details", {})

    if response.status_code == 429:
        retry_after = response.headers.get('Retry-After', '60')
        raise APIError(f"レート制限に達しました。{retry_after}秒後に再試行してください",
                      response.status_code, details)

    elif response.status_code >= 500:
        raise APIError(f"サーバーエラー: {message}", response.status_code, details)

    elif response.status_code >= 400:
        raise APIError(f"クライアントエラー: {message}", response.status_code, details)

    raise APIError(f"予期しないエラー: {message}", response.status_code, details)

def api_call_with_retry(url: str, method: str = 'GET', max_retries: int = 3, **kwargs) -> Dict[str, Any]:
    """自動リトライロジック付きAPI呼び出し"""

    for attempt in range(1, max_retries + 1):
        try:
            response = requests.request(method, url, **kwargs)
            return handle_api_response(response)

        except APIError as e:
            if e.status_code == 429:
                retry_after = int(e.details.get('retryAfter', 60))
                time.sleep(retry_after)
                continue

            elif e.status_code >= 500 and attempt < max_retries:
                delay = 2 ** attempt  # 指数バックオフ
                time.sleep(delay)
                continue

            raise

    raise APIError(f"最大リトライ回数({max_retries})を超えました")

次のステップ

レスポンス形式を理解したので、ActionsBlocks、またはDatasetsなどの特定のAPIセクションを参照し、これらのパターンを実際に確認してみましょう。