Semantic JSON diffing — comparing two JSON objects for meaningful differences rather than textual differences — requires solving three distinct problems: how to handle key ordering that differs without affecting meaning, how to compare arrays where order usually does matter, and how to represent the diff output in a format that's both human-readable and machine-executable
The previous articles on this site covered why JSON diff matters, practical diff workflows, structural diff fundamentals, JSON Patch as a standardised diff format, snapshot testing as JSON diffing, and why identical objects look different after normalization. This article addresses JSON diff in API versioning — specifically how JSON diff tools help manage API evolution, detect breaking changes, and build API governance workflows.
What makes an API change "breaking"
API breaking changes are changes that require existing API consumers to modify their code to continue functioning. Not all changes are breaking:
Breaking changes:
- Removing a field that consumers rely on
- Changing a field's type (string → integer, object → array)
- Renaming a field
- Changing a required field's semantics (changing what
status: "active"means) - Removing enum values that consumers might receive
- Changing HTTP method or URL path
Non-breaking (additive) changes:
- Adding a new optional field to a response
- Adding new enum values to a response field (though consumers need to handle unknown values gracefully)
- Adding a new endpoint
- Adding a new optional request parameter
JSON diff in this context: diffing the JSON Schema of API request and response bodies (or example response JSONs) between two versions reveals exactly what changed — and the nature of those changes determines whether the API version is a minor update or a major version bump.
Schema-level vs instance-level diffing
Two different levels of JSON diff serve different purposes:
Instance-level diff: comparing two specific JSON documents — an actual API response from yesterday vs today, or a test fixture vs the current output. Finds specific value differences.
Schema-level diff: comparing two JSON Schema definitions — the formal contract for what an API accepts and returns. Finds structural and type differences across all possible values, not just specific instances.
OpenAPI diff tools (oasdiff, openapi-diff, Spectral's breaking change rules) operate at the schema level — they compare openapi.yaml files or JSON Schema definitions and classify each difference as breaking or non-breaking according to documented rules.
The JSON diff tool use case for APIs: a quick instance-level diff between a real API response and the expected response (documented in a JSON fixture) reveals unexpected field additions, removals, or type changes that may have been introduced by a backend deployment.
The JSON Merge Patch RFC 7396: a simpler alternative to JSON Patch
JSON Patch (RFC 6902) — covered in the previous article — represents changes as an array of operation objects (add, remove, replace, move, copy, test). It's comprehensive but verbose.
JSON Merge Patch (RFC 7396) is a simpler format designed for partial updates:
A Merge Patch document is a JSON object where:
- Fields present with non-null values replace the corresponding fields in the target
- Fields with
nullvalues indicate deletion of that field - Fields absent from the patch are left unchanged in the target
// Original document
{
"name": "Alice",
"email": "[email protected]",
"age": 30
}
// Merge Patch (change email, remove age)
{
"email": "[email protected]",
"age": null
}
// Result
{
"name": "Alice",
"email": "[email protected]"
}
Limitations of Merge Patch: can't set a field to null (because null means deletion), can't operate on array elements without replacing the entire array, and can't express move operations. For these cases, JSON Patch is required.
HTTP PATCH with Merge Patch: many REST APIs use Content-Type: application/merge-patch+json with PATCH requests, sending the fields to update (and null for deletions). This is simpler to implement than JSON Patch for both API providers and consumers.
Array diffing algorithms: Myers vs Histogram vs patience
Diffing arrays in JSON is more complex than diffing objects because array elements are positionally sensitive (order matters), and small insertions or deletions cause subsequent elements to appear changed even when they haven't.
Three diff algorithms with different trade-offs:
Myers algorithm (used by Git's default diff): finds the minimum edit distance between two sequences. Optimised for small diffs on long files. Can produce confusing diffs when elements are moved rather than deleted and re-added.
Patience diff algorithm (used by Git's --patience flag): matches unique lines first, then recursively diffs the segments between matches. Produces more intuitive diffs when large blocks of content move.
Histogram algorithm (Git's default from v2.something): similar to patience but handles common subsequences better. Generally produces cleaner diffs than Myers for typical code changes.
For JSON arrays specifically: the appropriate algorithm depends on the array's semantics:
- Ordered arrays where position matters (steps in a recipe, items in a ranked list): Myers or Histogram, showing insertions and deletions at specific positions
- Sets of objects with unique identifiers: match on the ID field, then diff matching objects independently — much more readable than positional diffing
JSONPath and querying before diffing
Before diffing two large JSON documents, extracting and comparing specific subtrees is often more useful than diffing the full documents. JSONPath is the query language for this:
JSONPath syntax examples:
$.user.email— the email field inside user$.orders[0].items— items of the first order$.orders[*].status— status field of all orders$.orders[?(@.total > 100)]— orders where total exceeds 100
The workflow: use JSONPath to extract the specific sections of two documents that you care about, then diff those extracted sections. This is particularly useful for large API responses where only a subset of fields are relevant to the diff.
Automating JSON diff in CI/CD: contract testing
Contract testing uses JSON diff principles to verify that API responses match documented expectations:
Pact (consumer-driven contract testing): the consumer records the API calls and expected responses as a "pact" file. The provider runs the pact file as a test suite, comparing actual responses against the documented expectations. Differences in field names, types, or values fail the test.
The contract testing workflow:
- Consumer writes code against a known API response shape
- Consumer generates a contract (JSON document describing expected responses)
- Provider tests its actual responses against the contract using diff-style comparison
- Any breaking differences fail the build before deployment
Why this prevents breaking API changes: the CI pipeline runs contract tests on every provider deployment. If a developer accidentally removes a field that consumers depend on, the contract test catches it before the change reaches production.
How to use the JSON Diff tool on sadiqbd.com
- API response debugging: paste an expected API response (your test fixture or documented example) and the actual response from a live API call — the diff reveals what unexpectedly changed in a deployment
- Configuration drift detection: paste a production config JSON and a staging config JSON to identify settings that differ between environments — a common source of production-only bugs
- Schema evolution review: paste a v1 API response example and a v2 response example to visually identify all field additions, removals, and type changes before deciding whether to version the API
Frequently Asked Questions
If JSON Patch uses test, add, remove, replace operations, what's the best way to generate a JSON Patch from two JSON objects automatically?
Several libraries do this: fast-json-patch in JavaScript, jsonpatch in Python, and similar for other languages. These libraries implement the JSON Diff algorithm to produce a JSON Patch from two objects. The output is a valid RFC 6902 JSON Patch document that can be: applied to the first document to produce the second, stored as a compact representation of the change between two states, used as the body of an HTTP PATCH request. The generated patch is minimal but not always optimal for readability — it may use replace where a remove + add might be more semantically clear. For human review, the JSON diff visual output is more useful; for machine application, the JSON Patch is more practical.
Is the JSON Diff tool free? Yes — completely free, no sign-up required.
Try the JSON Diff tool free at sadiqbd.com — compare any two JSON documents and see structural differences instantly.