RESTful API データモデリング

RESTful APIデータモデリング:データ変更履歴の設計パターンと考慮事項

Tags: データモデリング, 履歴, 監査ログ, API設計, リソース設計, データ構造

はじめに

多くのアプリケーションにおいて、データの変更履歴を追跡し、必要に応じて参照できるようにすることは重要な要件となります。例えば、ユーザー設定の変更履歴、商品の価格改定履歴、注文の状態遷移履歴などです。これらの履歴データは、監査、問題調査、過去の状態の確認、さらにはデータの復元といった様々な目的で利用されます。

RESTful APIを通じてこれらのデータ変更履歴を提供または操作する場合、そのデータモデリングは慎重に行う必要があります。どのような情報を履歴として記録し、どのようにAPIリソースとして表現し、クライアントがどのように効率的にアクセスできるように設計するかが問われます。特に、データ量が時間とともに増大する履歴データにおいては、取得効率やパフォーマンスの考慮が不可欠です。

本記事では、RESTful APIでデータ変更履歴を扱う際のデータモデリングに関する考え方、具体的な設計パターン、そして設計を進める上で考慮すべき点について解説します。

データ変更履歴のユースケース

データ変更履歴が活用される主なユースケースをいくつか見てみましょう。

これらのユースケースは、APIが提供すべき履歴データの詳細度や取得方法に影響を与えます。

データ変更履歴をAPIで扱う上での課題

データ変更履歴のAPI設計にはいくつかの課題があります。

これらの課題を克服するために、適切なデータモデリングとAPIエンドポイント設計が重要になります。

データモデリングの考え方:何を履歴として記録するか

データ変更履歴のモデリングの最初のステップは、「何を記録するか」を定義することです。一般的に、以下の情報が履歴エンティティに含まれます。

履歴データは通常、対象データのリソースとは別のエンティティとしてモデリングします。例えば、User リソースに対する履歴であれば、UserHistory または AuditEvent のようなエンティティを考えます。

JSONでの履歴エンティティの例(差分方式の場合):

{
  "id": "history-item-id-123",
  "resourceType": "User",
  "resourceId": "user-id-456",
  "timestamp": "2023-10-27T10:30:00Z",
  "principalId": "user-id-abc",
  "changeType": "UPDATE",
  "changes": [
    {
      "field": "email",
      "oldValue": "old.email@example.com",
      "newValue": "new.email@example.com"
    },
    {
      "field": "status",
      "oldValue": "active",
      "newValue": "suspended"
    }
  ],
  "additionalInfo": {
    "apiEndpoint": "/users/user-id-456",
    "ipAddress": "192.168.1.10"
  }
}

JSONでの履歴エンティティの例(変更後のデータ全体方式の場合):

{
  "id": "history-item-id-124",
  "resourceType": "Order",
  "resourceId": "order-id-789",
  "timestamp": "2023-10-27T10:45:00Z",
  "principalId": "user-id-def",
  "changeType": "UPDATE",
  "snapshot": {
    "id": "order-id-789",
    "orderNumber": "ORD12345",
    "status": "processing",
    "totalAmount": {
      "amount": 10000,
      "currency": "JPY"
    },
    "items": [
      {
        "productId": "prod-a",
        "quantity": 1
      }
    ],
    "createdAt": "2023-10-27T10:00:00Z",
    "updatedAt": "2023-10-27T10:45:00Z"
  }
}

どちらの方式を採用するかは、データの特性、履歴の利用頻度、ストレージコスト、取得時の処理負荷などを総合的に考慮して判断します。

具体的な設計パターン:履歴リソースの表現

データ変更履歴をAPIで表現する主なパターンは、対象リソースのサブリソースとして扱う方法です。

パターン1: サブリソースとしての履歴 (/resources/{resourceId}/history)

これは最も一般的でRESTfulなアプローチの一つです。特定の対象リソースに紐づく履歴は、そのリソースのサブリソースとして表現します。

例:

このアプローチのメリットは、履歴がどのリソースに関連するものかが明確であり、URL構造が直感的であることです。また、特定のリソースに紐づく履歴のみを取得するため、不要なデータを取得するリスクを減らせます。

レスポンス構造の例 (GET /users/user-id-456/history):

{
  "items": [
    {
      "id": "history-item-id-123",
      "resourceType": "User",
      "resourceId": "user-id-456",
      "timestamp": "2023-10-27T10:30:00Z",
      "principalId": "user-id-abc",
      "changeType": "UPDATE",
      "changes": [...] // または snapshot
    },
    {
      "id": "history-item-id-125",
      "resourceType": "User",
      "resourceId": "user-id-456",
      "timestamp": "2023-10-27T09:00:00Z",
      "principalId": "user-id-xyz",
      "changeType": "CREATE",
      "changes": [...] // または snapshot
    }
  ],
  "pagination": {
    "next": "/users/user-id-456/history?offset=20&limit=20",
    "totalItems": 100
  }
}

これは履歴アイテムのリストを返すため、通常はページネーションに対応させる必要があります。

パターン2: 独立したリソースとしての履歴 (/audit-events/history)

システム全体の監査ログや履歴を、単一のエンドポイントで提供する場合に考えられます。

例:

このパターンでは、クエリパラメータを使って取得したい履歴を絞り込むことが一般的です。resourceTyperesourceId でフィルタリングすることで、特定リソースの履歴も取得できます (GET /audit-events?resourceType=User&resourceId=user-id-456)。

メリットは、システム全体の履歴を横断的に検索・取得しやすい点です。デメリットは、デフォルトで全履歴が対象となるため、クエリパラメータによる絞り込みを適切に行わないと、非常に大量のデータを扱うことになりパフォーマンス問題を起こしやすい点です。また、URL構造からは対象リソースとの関連性がサブリソースパターンほど明確ではありません。

多くの場合、特定リソースの履歴参照が主目的であればサブリソースパターン、システム全体の監査や横断的な分析が主目的であれば独立リソースパターンが適しています。両方のニーズがある場合は、両方のエンドポイントを提供する設計も考えられます。

履歴データの取得方法

履歴データは量が多いため、取得方法の設計が非常に重要です。

アンチパターン

データ変更履歴のAPI設計におけるアンチパターンをいくつか挙げます。

設計上の考慮事項

まとめ

データ変更履歴のRESTful APIデータモデリングは、単に対象データの履歴情報を返すだけでなく、データ量の増大への対応、多様な取得要件への適合、そしてパフォーマンスとセキュリティの確保を考慮した多角的な設計が求められます。

多くの場合、対象リソースのサブリソースとして履歴を提供するか、システム全体の独立した履歴リソースとして提供するパターンが有効です。どちらのパターンを選択するにしても、ページネーション、フィルタリング、ソートといった効率的な取得手段を提供することが不可欠です。また、履歴として何を記録するか(差分か全体か)、操作主体やタイムスタンプを含めるかといったデータ構造の設計も、後の利用目的に合わせて慎重に行う必要があります。

本記事で解説した設計パターンや考慮事項が、皆さんのデータ変更履歴に関するAPI設計の一助となれば幸いです。