Practical API testing guide
How to compare two API responses
A useful API comparison checks more than whether two JSON documents look similar. It asks whether both endpoints produce the same contract, meaning, and user-visible behavior under equivalent conditions.
What should an API comparison cover?
Start with five layers: HTTP status, response headers, body structure, field values, and response time. A change at any layer can affect clients. For example, a response can keep the same values but change an identifier from a number to a string, breaking strict consumers even though the data still looks readable.
1. Choose a baseline and a candidate
Treat Environment A as the known baseline: usually the current production API or the version your clients already support. Treat Environment B as the candidate: a new version, rewritten service, staging environment, or alternate provider.
Write down what you expect to change before testing. Intentional changes might include a new field or a renamed property. Anything outside that list deserves investigation. This simple step prevents expected differences from hiding unexpected regressions.
2. Send equivalent requests
Use the same HTTP method, logically equivalent resource identifiers, matching query parameters, and the same request body. Send compatible headers to both endpoints. If the environments require different tokens, keep the permissions and test data equivalent.
Use test accounts and short-lived tokens. Never paste production secrets into an online comparison tool. Confirm that you are authorized to call both endpoints.
3. Compare status codes and headers first
Status codes explain the broad outcome before you inspect the body. A 200 versus 404 difference is more important than dozens of JSON changes caused by the missing resource. Also check whether one API returns 201 after creation while the other returns 200, because client code may depend on that distinction.
Review response headers that are part of the contract: Content-Type, caching directives, rate-limit fields, pagination links, request IDs, and deprecation notices. Ignore volatile infrastructure headers unless they matter to your clients.
4. Compare JSON structure, types, and values
A field-by-field JSON diff should classify changes instead of treating every mismatch equally. Removed fields and type changes are usually more dangerous than added optional fields. Value changes require context: a different timestamp may be normal, while a different account status may signal a data or business-logic problem.
{
"id": 42,
"name": "Avery Chen",
"plan": "pro",
"active": true
}{
"id": "42",
"fullName": "Avery Chen",
"plan": "pro",
"active": true,
"region": "us-east"
}In this example, name was renamed to fullName, id changed from a number to a string, and region was added. The added field may be safe, but the rename and type change can break existing clients.
Worked migration example: interpret all four differences
The customer responses above are fictional fixtures. Assume both endpoints return HTTP 200 for the same customer and that existing clients require a numeric ID and a name. The comparator reports four differences; it does not infer that two fields represent a rename.
| JSON path | Change | Baseline → candidate | What to investigate |
|---|---|---|---|
$.id | type | 42 (number) → "42" (string) | A typed client expecting a number may fail to deserialize the response. |
$.name | removed | "Avery Chen" → missing | The existing profile screen may lose the customer name. |
$.fullName | added | missing → "Avery Chen" | A new property does not automatically replace the old property for clients. |
$.region | added | missing → "us-east" | Usually additive, but check clients that reject unknown fields. |
Decision under this contract: do not treat this migration as backward compatible. Restore the numeric ID and the original name property, or deliberately version the API and migrate its clients. The unchanged plan and active fields do not appear in the differences list.
{
"id": 42,
"name": "Avery Chen",
"plan": "pro",
"active": true,
"region": "us-east"
}Path: $.region Change: added Baseline: missing Candidate: "us-east" Expected differences: 1 Review: can clients accept this new field?
A remaining difference is not automatically a failed release. Here the extra region property can be acceptable if the API contract allows it and consumer tests pass. Record the reason for accepting it rather than hiding the difference.
Try a comparison with public sample endpoints
Open the comparator and keep GET selected. Its starting examples use JSONPlaceholder posts 1 and 2. These are different records, so differences are expected; this demonstrates the interface rather than proving a migration regression.
- Set Environment A to
https://jsonplaceholder.typicode.com/posts/1. - Set Environment B to
https://jsonplaceholder.typicode.com/posts/2. - Keep the Accept header set to application/json and click Run comparison.
- With the standard sample responses, expect changes at
$.id,$.title, and$.body. The userId is the same. External sample data and availability can change. - Set both environments to posts/1 and run again. If both requests succeed with identical data and status, the tool should report a match.
The customer JSON example in this guide is for learning. To compare your own fixtures with the current tool, serve them from two public HTTPS test endpoints you control; the comparator accepts endpoint URLs, not pasted response documents. Never expose a private service just to use this demo.
Open the comparator and try the sampleThree differences that need context
The report displays at most 300 differences. A match describes the two observed responses, not every possible request. Check headers separately where the report does not explicitly show a comparison, and use repeated tests for timing decisions.
5. Interpret response-time differences carefully
A single timing result is a clue, not a benchmark. Network distance, cold starts, cache state, server load, and third-party dependencies can affect each request. Repeat the comparison under similar conditions before deciding that one API is faster.
For performance decisions, use dedicated load-testing and monitoring tools. API Comparator’s timing is best for spotting large or surprising differences during a quick functional check.
6. Separate intentional changes from regressions
Review each difference against the planned API contract. Record intentional changes in release notes and migration documentation. For unexpected differences, identify whether the cause is routing, authentication, data, serialization, validation, or business logic before shipping.
- Expected status code and content type
- Required fields still exist
- Field types remain compatible
- Null, empty, and missing values behave as expected
- Errors use a documented structure
- Large timing differences were retested
Common comparison mistakes
Comparing different records, using tokens with different permissions, ignoring ordering in arrays, and testing only successful requests can all produce misleading conclusions. Include empty results, invalid input, expired credentials, missing resources, and rate-limit behavior in a complete migration test plan.
Compare your endpoints
Start with one representative request, inspect the important differences, and then repeat the process across the critical paths your users depend on.
Open API Comparator