スタージングAPIは200を返します。プロダクションAPIも200を返します。しかし、どこかの下流で問題が発生し、あなたは二つのJSONブロブを比較して何が変わったかを調べようとしています。
JSONの比較は、実際に比較しているときに簡単には見えません。
JSON比較が見えていない理由
JSONには標準形式がありません。二つのオブジェクトは同じデータを表しても、実際に見るとまったく異なるように見えます。開発者に bite する点はここです:
キーの順序。 JSONオブジェクトは仕様上順序がありません — {"a":1,"b":2} と {"b":2,"a":1} 意味的に同じですが、raw stringとして比較すると異なるように見えます。
空白文字。 ミニフィードと整形されたJSONは文字列比較で失敗します。同じデータでも異なるバイトです。
整数の列はJSONの数値に変換され、true/falseの値を持つ列は論理値に変換されます。しかし、ZIPコードのような整数に見える列(90210)は文字列として保持すべきです — 変換すると先頭のゼロが失われます。 "1" と 1 異なるJSON値です。そして null および欠落したキー。あなたの差分ツールはこの区別を気にする必要があります——そしてあなたも、なぜならAPIの消費者がそれらを同じように扱わない可能性があるからです。
ネストの深さ。 大きな応答の中の5段階深い変更値は、raw出力を見ているときに容易に見過ごされてしまいます。
構造的等価性と意味的等価性
APIの変更をデバッグするときにこの区別が重要です。
構造的等価性 正規化後のJSONがバイトごとに完全に同じであることを意味します——同じキー、同じ値、同じ順序。キャッシュ検証や署名チェックに役立ちます。
意味的等価性 データが同じことを表していることを意味します。構造が異なる場合でも、応答が user_id に userIdをリネームしたり、新しいオプションフィールドを追加したりしても、意味的に異なるものの、消費者にとって機能的に同等である可能性があります。
回帰テストでは通常、構造的等価性が必要です。API消費者向けの破壊的な変更を評価する場合は、意味的等価性が適切なフレームです。
ターミナルでJSONを差分比較する方法
の場合、クッキーは jq と diff
jq キーをソートし、空白を正規化することで、差分比較の前にしっかりした前処理ステップになります:
diff <(jq --sort-keys . response_v1.json) <(jq --sort-keys . response_v2.json)
これはキーの順序とフォーマットを処理します。実際のデータの違いだけを表示します。さらに -c を追加してコンパクトな差分出力を得たり、 -u を追加して統一形式を得ることができます。
ライブAPI応答と保存されたベースラインを比較する場合:
diff <(jq --sort-keys . baseline.json) <(curl -s https://api.example.com/endpoint | jq --sort-keys .)
Pythonの deepdiff
構造化出力が必要な場合——特にネストされたオブジェクトや配列の場合—— deepdiff プログラム的に何が変わったかを表示します:
from deepdiff import DeepDiff
import json
with open("response_v1.json") as f:
v1 = json.load(f)
with open("response_v2.json") as f:
v2 = json.load(f)
diff = DeepDiff(v1, v2, ignore_order=True)
print(diff.to_json(indent=2))
DeepDiff 変更を分類します: values_changed, dictionary_item_added, dictionary_item_removed, type_changes。これはCIでの回帰チェックをスクリプト化しやすくなります。
インストール方法は: pip install deepdiff
一般的な使用例
環境間のAPI応答の比較。 スタージングとプロダクションは同じ構造を返すべきです。デプロイ後にすぐにjqで差分を取ることで、ユーザーが実際に気づく前にスキーマのずれを検出できます。
時間経過によるスキーマのずれを検出する。 APIは進化します。保存されたベースラインをピン留めし、毎回デプロイ時に差分を実行することで、正確にいつ何が変わったかを追跡できます——バグレポートから発見するのではなく。
回帰テスト。 期待される応答を記録し、API呼び出しを再現し、出力を差分比較します。これは特にスキーマをコントロールできない第三者APIに非常に有用です。
配列比較の課題
配列はJSON差分ツールが混乱する場所です。仕様上、JSON配列の順序は重要であり、ほとんどの差分ツールは再順序された配列を変更された値の系列として扱い、混乱し、ノイズを生み出します。
APIがタグのリストを返す場合、タグが異なる順序で返された場合、単純な差分はすべての要素を変更として表示します:
- "tags": ["json", "api", "rest"]
+ "tags": ["api", "json", "rest"]
ツールのように deepdiff で ignore_order=True を設定できます。 jq はデフォルトで配列をソートしません——既知の配列フィールドに対して sort をパイプ通す必要があります。
実用的なルール:APIで配列の順序が意味的に重要でない場合(たとえばタグリストの場合)、順序を無視できる差分ツールを使用します。順序が重要である場合(たとえばソートされた結果リストの場合)、それを無視しないでください。
JSONスキーマ検証を使用するべきタイミング
差分は瞬間的な比較です——二つの特定の応答の違いを示します。JSONスキーマ検証は応答が契約に従っているかどうかを示します。
次の場合はJSONスキーマ検証を使用します:
- すべての応答に対して構造を強制したい場合
- 公開APIを公開し、バックワード互換性を保証したい場合
- 欠落した必須フィールドや誤った型を検出したい場合(値の変更ではなく)
差分ツールを使用する場合は:
- 二つの特定の応答があり、何が変わったかを理解したい場合
- APIバージョン間の回帰をデバッグしたい場合
- デプロイをチェックしたい場合
これらは異なる問題を解決します。本格的なAPIテストでは、両方を使用したいです。
速い選択肢:IO Tools JSON Compareを使用
簡単なブラウザベースの差分を実行するための設定なしで、 IO Tools JSON Compare キーの順序、空白の正規化、ネストされたオブジェクト、型認識比較の一般的なケースを処理します。二つのJSONオブジェクトを貼り付けて、クリーンなサイドバイサイド差分を得られます。
デバッグ中でターミナルを開く必要がない場合に便利です。
迅速なリファレンス:異なるアプローチが何を検出するか
| シナリオ | 文字列差分 | jq + diff |
deepdiff |
JSONスキーマ |
|---|---|---|---|---|
| キーの順序が異なる | 欠落 | 検出 | 検出 | 欠落 |
| 追加の空白文字 | 欠落 | 検出 | 検出 | 欠落 |
型ミスマッチ("1" vs 1) |
検出 | 検出 | 検出 | 検出 |
| Null vs 欠落キー | 検出 | 検出 | 検出 | 検出 |
| 配列の順序変更 | 偽陽性 | 偽陽性 | 設定可能 | 欠落 |
| 追加されたオプションフィールド | 検出 | 検出 | 検出 | 設定可能 |
| スキーマ契約違反 | 欠落 | 欠落 | 欠落 | 検出 |
デバッグする内容に応じて正しいツールが異なります。簡単なチェックには jq --sort-keys plus diff がほとんどのケースをカバーします。CI回帰テストには deepdiff 構造的、スクリプト可能な出力を提供します。スキーマの強制にはJSONスキーマ。そして、ターミナルを開く必要がない場合に、ブラウザベースのJSON差分ツールで数秒で答えを得られます。
