QA How-To
Testing API versioning (2026)
Learn testing API versioning across contracts, consumers, shared state, security, deprecation, sunset, migrations, and CI with runnable Node.js examples.
21 min read | 3,715 words
TL;DR
Testing API versioning combines selector tests, contract analysis, historical consumer replay, version-specific behavior, cross-version state, security parity, and migration rehearsal. Deprecation and sunset behavior also need explicit, standards-aware assertions.
Key Takeaways
- An API version is a consumer behavior contract, not merely a path label or build number.
- Combine OpenAPI diffing with real consumer requests because schema compatibility cannot prove semantics.
- Test valid, missing, malformed, unknown, retired, duplicate, and conflicting version selectors.
- Cross-version workflows reveal lossy mappings, changed defaults, stale writes, and event-version defects.
- Run the same authentication, authorization, rate, cache, and tenant matrix against every supported version.
- RFC 9745 Deprecation and RFC 8594 Sunset provide distinct lifecycle signals when the API adopts them.
- Mixed-deployment, database migration, asynchronous work, and rollback tests are part of version assurance.
Testing API versioning means proving that each supported contract behaves as documented, old consumers keep working during the support window, new behavior is isolated to the intended version, and deprecation or retirement signals give clients a safe migration path.
The URL is only one part of the problem. Version selection can occur in a path, media type, header, query parameter, host, or negotiated client capability. A complete QA strategy checks routing, request and response compatibility, state shared across versions, security parity, observability, documentation, and the eventual sunset behavior.
TL;DR
| Risk | Essential test |
|---|---|
| Wrong version selected | Assert response contract and version signal for every selector |
| Old client breaks | Replay representative old consumer requests against the new deployment |
| New fields leak backward | Compare version-specific response shapes and semantics |
| Shared state diverges | Create in one version, read or update through another as supported |
| Security drifts | Run the same auth and tenant matrix across every live version |
| Caches mix versions | Request the same resource with different selectors and identities |
| Deprecation is invisible | Assert Deprecation, Link, and Sunset policy where adopted |
| Retirement is unsafe | Verify the documented post-sunset response and no hidden route bypass |
Treat every version as a consumer contract plus a migration state. Schema diffing is useful, but only behavioral and cross-version tests can prove that the deployment preserves meaning and shared data correctly.
1. Define Testing API Versioning as Contract Compatibility
An API version is a promise about how a client selects behavior and how the service interprets requests and constructs responses. The version label may be v1, a date, a media type parameter, or another documented identifier. It is not the same as the HTTP protocol version, the OpenAPI Specification version, the build number, or the internal service release.
Begin with compatibility in consumer language. A compatible change lets a supported consumer continue to achieve its documented task without code changes. Adding an optional response member is usually structurally compatible for tolerant JSON clients, but it can still break a client with strict deserialization. Changing the meaning of status: ACTIVE is behaviorally breaking even when the schema is identical.
Define invariants for every live version:
- The documented selector resolves to exactly one intended contract.
- Requests valid for that version retain their meaning through new deployments.
- Unsupported or ambiguous versions fail predictably, not by falling back silently.
- Shared resources remain consistent across versions where interoperability is promised.
- Authentication, authorization, rate limits, and validation are not weaker on old versions.
- Deprecation and retirement follow the published dates and response policy.
Testing API versioning therefore combines contract tests, consumer replay, cross-version state tests, and operational checks. A green schema diff cannot prove defaults, calculations, authorization, or event behavior.
Keep a version support inventory with owner, selector, first release, deprecation date, sunset date, documentation, specification artifact, known consumers, and environment availability. Without that inventory, QA cannot know which contracts the release must protect.
2. Compare Version Selection Strategies and Their Test Risks
No selection strategy is automatically correct. Choose test cases from the architecture in use and be especially careful when a platform supports more than one strategy during migration.
| Strategy | Example | Useful property | Primary QA risk |
|---|---|---|---|
| Path | /v2/orders/123 |
Visible and easy to route | Old and new routes drift or share handlers unexpectedly |
| Media type | Accept: application/vnd.example.order+json;version=2 |
Uses content negotiation | Proxy cache ignores Accept, parser defaults silently |
| Custom header | API-Version: 2026-04-01 |
Keeps resource path stable | Header stripped, omitted from cache key, or unsupported by tooling |
| Query parameter | /orders/123?api-version=2 |
Easy for some clients | URLs and cache rules become ambiguous |
| Host | v2.api.example.test |
Strong routing separation | DNS, TLS, CORS, or gateway policy differs |
| Date-based contract | 2026-04-01 selector |
Maps behavior to release policy | Boundary dates, aliases, and documentation diverge |
For every selector, test valid values, missing value, malformed value, unknown future value, retired value, whitespace, duplicate values, case rules, and conflicts between two selectors. If both /v2 and API-Version: 1 arrive, reject the ambiguity or apply one explicitly documented precedence rule. Silent, component-dependent precedence causes security and support defects.
HTTP header field names are case-insensitive, but values follow the contract. Media type parameters and negotiation need standards-aware parsing rather than fragile string equality. Test multiple Accept values and quality weights if the service promises negotiation.
Version selection must also influence caching correctly. Request the same resource through two versions and confirm an intermediary never serves the wrong representation. Headers such as Vary can support correct caching, but behavior must be tested through the deployed cache.
3. Inventory the Contract, Consumers, and Breaking-Change Policy
Before authoring tests, collect the OpenAPI descriptions, examples, changelog, migration guide, support policy, and representative consumer operations for every live version. Record whether one specification uses multiple servers or paths, or each version has a separate document. The info.version value describes the API document, while the top-level openapi value identifies the OpenAPI feature set. Neither automatically selects the runtime API version.
Define the organization's breaking-change policy with concrete examples. Common breaking changes include removing an operation or field, renaming a member, making an optional request field required, narrowing an accepted value, changing a type, removing an enum value, changing authentication, altering pagination, and changing error codes consumers depend on.
Potentially compatible changes still need risk review:
- Adding an optional response property can break strict clients.
- Adding an enum value can break exhaustive switches.
- Tightening undocumented validation can reject real historical data.
- Changing default page size affects client behavior and load.
- Improving sort order can break consumers that relied on the old accidental order.
- Adding a required response header can expose proxy differences.
Build a consumer corpus from real, sanitized request shapes and client-owned contract tests. Rank it by traffic and business impact, but retain low-volume critical integrations. A frequently called read endpoint and a monthly payroll export can both be release blockers for different reasons.
Connect provider checks with API contract testing using Pact when consumer-driven contracts fit the architecture. Consumer contracts complement, rather than replace, provider specifications and exploratory compatibility testing.
4. Use OpenAPI Diffing Without Treating It as Proof
OpenAPI provides a machine-readable HTTP interface description. In 2026, OpenAPI 3.2.0 is the latest published feature set, but many production ecosystems still use 3.0 or 3.1. Use the version your tooling and consumers actually support. Do not mechanically rewrite a description to 3.2 merely to appear current.
A diff gate should compare the proposed contract against the accepted baseline for each supported version. Classify removed paths and methods, parameter location or requiredness changes, request schema narrowing, response status removal, property type and requiredness changes, security scheme changes, and server URL changes. Review tool output because compatibility depends on direction and consumer behavior.
Example baseline and candidate fragments:
# v1 baseline
openapi: 3.1.0
info:
title: Orders API
version: 1.8.0
paths:
/v1/orders/{id}:
get:
responses:
'200':
description: Order found
content:
application/json:
schema:
type: object
required: [id, total]
properties:
id: { type: string }
total: { type: integer }
# Unsafe candidate for the same v1 contract
openapi: 3.1.0
info:
title: Orders API
version: 1.9.0
paths:
/v1/orders/{id}:
get:
responses:
'200':
description: Order found
content:
application/json:
schema:
type: object
required: [id, total]
properties:
id: { type: string }
total: { type: string }
Changing total from integer minor units to a formatted string is breaking within v1 even though both are valid JSON. It belongs in a new contract version or a new additive field with a migration plan.
Run schema validation and example validation, then run behavior tests. Specification files can be stale, incomplete, or interpreted differently by generators. The OpenAPI schema testing guide covers response validation and specification quality in more depth.
5. Create Runnable Cross-Version Tests with Node.js
The following test uses built-in Node.js fetch, node:test, and strict assertions. It assumes path-based versions of a QA Orders API. It creates through v1, reads through both versions, and proves the representations differ intentionally while sharing resource identity.
import test from 'node:test';
import assert from 'node:assert/strict';
const baseUrl = new URL(process.env.API_BASE_URL ?? '');
const token = process.env.API_TEST_TOKEN;
const allowedHosts = new Set(['localhost', '127.0.0.1', 'orders.qa.example.test']);
assert.ok(allowedHosts.has(baseUrl.hostname), `Unapproved host: ${baseUrl.hostname}`);
assert.ok(token, 'API_TEST_TOKEN is required');
async function api(path, { method = 'GET', body, headers = {} } = {}) {
const response = await fetch(new URL(path, baseUrl), {
method,
headers: {
authorization: `Bearer ${token}`,
accept: 'application/json',
...(body === undefined ? {} : { 'content-type': 'application/json' }),
...headers,
},
body: body === undefined ? undefined : JSON.stringify(body),
signal: AbortSignal.timeout(10_000),
});
const text = await response.text();
return {
response,
payload: text ? JSON.parse(text) : null,
};
}
test('v1 and v2 expose one order with version-specific representations', async () => {
const clientReference = `version-${crypto.randomUUID()}`;
const created = await api('/v1/orders', {
method: 'POST',
body: {
clientReference,
currency: 'USD',
totalMinor: 2599,
},
});
assert.equal(created.response.status, 201);
const id = created.payload.id;
assert.ok(id);
const [v1, v2] = await Promise.all([
api(`/v1/orders/${encodeURIComponent(id)}`),
api(`/v2/orders/${encodeURIComponent(id)}`),
]);
assert.equal(v1.response.status, 200);
assert.equal(v2.response.status, 200);
assert.equal(v1.payload.id, id);
assert.equal(v2.payload.id, id);
assert.equal(v1.payload.totalMinor, 2599);
assert.equal(v1.payload.currency, 'USD');
assert.equal(Object.hasOwn(v1.payload, 'money'), false);
assert.deepEqual(v2.payload.money, { amountMinor: 2599, currency: 'USD' });
assert.equal(Object.hasOwn(v2.payload, 'totalMinor'), false);
});
test('unknown version fails without falling back', async () => {
const { response, payload } = await api('/v999/orders/example');
assert.equal(response.status, 404);
assert.equal(payload.code, 'API_VERSION_NOT_SUPPORTED');
});
API_BASE_URL=https://orders.qa.example.test \
API_TEST_TOKEN=short-lived-qa-token \
node --test api-versioning.test.mjs
Adapt statuses and schemas to the documented API. The important pattern is shared identity plus explicit version-specific assertions. Do not compare entire responses blindly because intentional representation differences are the purpose of the test.
6. Test Request Compatibility, Defaults, and Validation
Version tests must send historical request shapes, not only the newest SDK's shape to every route. Preserve a corpus of v1 create, update, search, pagination, and error requests. Include omitted optional fields, old enum values, historical date formats, empty collections, maximum boundaries, and content types used by real consumers.
Defaults are a major source of semantic breaks. Suppose v1 omitted notifyCustomer and defaulted to false, while v2 defaults to true. Reusing one internal request model without version-aware mapping can make old v1 clients send notifications after a deployment. Write a test that omits the field in each version and asserts both state and side effect.
Test unknown fields according to each contract. Some servers ignore unknown JSON members for forward compatibility, while others reject them. Strictness is not universally better. It must be stable within a supported version and documented so generated clients behave predictably.
Validation can evolve in a new version, but old behavior may need preservation. If v2 rejects a legacy phone format, decide whether v1 still accepts it, whether stored v1 records remain readable through v2, and how clients migrate. Test boundary values around every narrowed rule.
For updates, verify partial and replacement semantics separately. A new field with a server default can accidentally overwrite data when an old client sends a full replacement. Create through v2 with the new field, update through v1, and assert whether the v2-only value remains, resets, or makes cross-version update unsupported according to contract.
Malformed and ambiguous selectors must fail before business work. Assert no record, event, or quota-consuming job is created. Version routing errors should use a stable machine code and identify supported migration information without leaking internal route configuration.
7. Verify Response Compatibility and Error Semantics
Response compatibility includes more than member names. Test types, nullability, units, enum values, precision, time zones, ordering, pagination links, status codes, error shapes, headers, and caching metadata. A version change from dollars to minor units, local time to UTC, or nullable to omitted can be more significant than a renamed field.
Create golden semantic examples from controlled data. For one order, define expected v1 and v2 representations and the mapping between them. Assert common invariants such as ID, ownership, amount, and lifecycle state, then assert deliberate differences. This avoids duplicating unrelated assertions while making migration behavior explicit.
Error contracts need version coverage too. Test validation, authentication, authorization, not found, conflict, rate limit, and internal dependency failure. A new problem-details format in v2 should not leak into v1 if clients parse the old shape. Gateways must route versioned errors consistently even when the application is unavailable.
Status changes can break clients. Replacing 404 with 200 plus found: false, or 409 with 422, is a contract change even if both seem defensible. Keep stable behavior within the version. Additive headers are usually safer, but strict clients and CORS exposure still require review.
Pagination is particularly sensitive. Verify default and maximum page size, cursor opacity, stable sorting, continuation across versions, and links that preserve the selected version. A v1 next URL must not send the consumer to v2 accidentally.
Use API error handling and negative testing to design a reusable error matrix across versions.
8. Test Shared State and Cross-Version Workflows
Many API versions are different views over one underlying domain. Test the combinations the support policy allows: create in v1 and read in v2, create in v2 and read in v1, update in one and read in the other, cancel through the old version, and process callbacks or asynchronous jobs created by each.
Not every direction must work. A v2-only resource type may have no valid v1 representation. The API should reject or omit it predictably rather than corrupting data. Document these asymmetries and test them explicitly.
Shared-state cases expose lossy mapping. If v2 adds multiple shipping addresses while v1 supports one, a v1 update could discard v2 data. Options include blocking that update, preserving unknown fields internally, defining a primary address mapping, or making versions operate on separate resource models. QA should enforce the chosen rule and its user impact.
Test optimistic concurrency across versions. If both expose an ETag or revision, a stale update from v1 must not overwrite a newer v2 update unnoticed. Send competing changes with the same expected revision and assert the documented conflict. Check final state and events.
Events and webhooks also require version ownership. Determine whether event schema follows the API request version, its own independent version, or the current domain schema. Create through each API version and assert the intended event contract. A consumer should not receive a silently upgraded payload because a different client used v2.
Data migration tests should cover pre-existing v1 records, mixed-version records, defaults for newly introduced fields, rollback, and repeated migration execution. A fresh database populated only through v2 will miss the highest-risk compatibility defects.
9. Check Security and Policy Parity Across Versions
Older versions are attractive attack surfaces because they receive fewer feature changes and sometimes fewer security tests. Run the same authentication, scope, tenant, object, property, and rate-limit matrix against every supported version. A secure v2 does not compensate for a vulnerable v1 route over the same data.
Compare security scheme declarations and runtime behavior. Test anonymous calls, invalid and expired credentials, low-scope callers, cross-tenant IDs, mass-assignment fields, bulk routes, exports, and administrative operations. Verify old field names cannot still change a now-protected property.
Gateway policy must include every selector and alias. Try alternate capitalization, trailing slashes, duplicate separators, legacy hosts, undocumented query selectors, and conflicting headers. The expected result is normal routing or safe rejection, never bypass to an unprotected handler.
Rate limits and input-size limits should reflect risk across versions. If v1 returns a larger payload or supports a more expensive search, it may need a different documented cost, but it should not have no limit because a new plugin was configured only for v2.
Check CORS, cache, and content-type policies. A cache key that omits the version header can leak a v2 response to a v1 consumer or cross an identity boundary. An old version that accepts form content while the new version requires JSON may have different cross-site request risks. Test actual browser and intermediary behavior where relevant.
When a security fix changes behavior, decide whether to backport it despite strict compatibility. Security usually outweighs preserving vulnerable behavior. Document the exception, run consumer regression, and provide a migration note rather than hiding the change.
10. Validate Deprecation and Sunset Signals
Deprecation means a resource or version remains usable but clients are encouraged to migrate. Sunset indicates an expected time after which it may become unavailable. These are different states and should produce different tests.
RFC 9745 standardizes the Deprecation response header. Its value is a Structured Field date such as @1782863999, not an arbitrary true string. A Link header with rel="deprecation" can point to migration documentation. RFC 8594 defines Sunset using an HTTP date.
An illustrative response is:
HTTP/1.1 200 OK
Content-Type: application/json
Deprecation: @1782863999
Sunset: Thu, 31 Dec 2026 23:59:59 GMT
Link: <https://developer.example.test/migrations/orders-v2>; rel="deprecation"; type="text/html"
Test that the deprecation timestamp matches policy, the sunset is not earlier, and the link uses an approved HTTPS origin. Verify headers appear on every affected response, including errors where practical, and do not appear on unaffected versions. If a gateway adds them, ensure application and gateway clocks or configuration do not conflict.
Deprecation must not itself change resource behavior. The old contract remains supported until its policy says otherwise. Monitor usage by safe client identity and operation so teams can contact remaining consumers without logging secrets or high-cardinality resource IDs.
Before sunset, run the old consumer corpus against the intended final deployment. After sunset in a controlled environment or simulated clock, assert the documented response, such as 410 or a version-specific error, and confirm migration links remain available. Search for legacy hostnames and alternate routes that bypass retirement.
11. Rehearse Migration, Rollback, and Mixed Deployments
Version rollouts often run mixed application and gateway revisions. Test one old and one new instance behind the load balancer. Every request for v1 must behave consistently regardless of node. A selector understood only by new nodes should not produce intermittent v2 success and v1 fallback.
Rehearse database changes with old and new application code. Expand-and-contract migrations are common: add compatible storage, deploy code that can read both forms, migrate data, switch writes, then remove old storage only after rollback is no longer required. QA should verify reads, writes, background jobs, and rollback at each stage.
Create data before deployment, during mixed mode, and after cutover. Read and update it through supported versions. Exercise long-running jobs, webhooks, and queued messages created by the old code but processed by the new code. These asynchronous boundaries often outlive the deployment that created them.
Test feature flags independently from public API versions. A flag should not cause two clients using the same version to receive incompatible contracts unless segmentation is explicitly part of the contract. Preserve flag state and cohort in diagnostics.
Rollback testing asks whether new writes remain readable by old code. If v2 introduces a state the old release cannot understand, rollback may require a compatibility mode or forward fix. Identify this before production deployment, not during an incident.
Capture version selector, selected contract, application revision, gateway revision, schema or migration level, and correlation ID in safe telemetry. That evidence distinguishes a contract defect from a mixed-fleet routing defect.
12. Operationalize Testing API Versioning in CI
Use several gates with different responsibilities. Specification linting and diffing run first. Provider unit and component tests protect version adapters, defaults, and mappings. Consumer contract verification and historical request replay protect usage. Deployed API tests cover selection, security, cache behavior, and shared state. Migration rehearsals run before risky releases.
A pull request should not update a supported contract baseline automatically just because the diff is red. Require an explicit compatibility decision and versioning review. Baselines represent accepted consumer promises, not snapshots of whatever the provider currently emits.
Parallelize version suites while isolating their data. Tag each record with a run ID and creating version. Cross-version tests should own their resources so unrelated workers cannot update them. Keep old SDKs or serialized requests in reproducible containers rather than rebuilding them against the latest model.
Publish a compatibility report by live version: schema diff, consumer contracts, historical corpus, security parity, shared-state workflows, deprecation headers, and sunset rehearsal. Track failures to an owner and support deadline.
Retire tests only after the corresponding version is removed from every public route, gateway, job processor, webhook path, documentation page, and rollback plan. Keep a small post-retirement probe to detect accidental reintroduction where appropriate.
Testing API versioning becomes manageable when each version has an explicit owner, contract baseline, consumer evidence, and lifecycle state. The suite then supports both safe change and deliberate retirement.
Interview Questions and Answers
Q: What does API versioning testing verify beyond the URL?
It verifies version selection, request and response semantics, old-consumer compatibility, shared state, security parity, caching, documentation, and lifecycle signals. A path such as /v2 only proves one routing input. The behavior behind it must remain a coherent contract.
Q: How do you identify a breaking API change?
I compare the proposed behavior with the supported consumer contract. Removals, required inputs, type changes, narrowed values, changed defaults, status changes, and semantic reinterpretation can all break clients. I combine schema diffing with real consumer requests because schemas cannot detect every behavioral dependency.
Q: Which versioning strategy is best?
There is no universal best strategy. Paths are visible, headers keep resource identifiers stable, and media types use content negotiation, but each has routing, caching, and tooling tradeoffs. I test the strategy the product documents and reject ambiguous selector combinations.
Q: How would you test v1 and v2 over shared data?
I create in each version and read or update through the other where supported. I assert common domain invariants plus deliberate representation differences. I focus on lossy mappings, defaults, new states, optimistic concurrency, and event schemas.
Q: What is the role of OpenAPI diffing?
It is an early compatibility signal for structural changes in paths, parameters, schemas, responses, and security. It is not proof because the description can be stale and behavior can change without schema changes. I pair it with consumer contracts and behavioral tests.
Q: How do you test API deprecation in 2026?
If the service adopts the standards, I validate RFC 9745 Deprecation, a deprecation link, and RFC 8594 Sunset. I check scope, dates, HTTPS documentation, cache visibility, and behavior before and after the simulated cutoff. Deprecation itself should not change the old contract.
Q: Why should security tests run against old API versions?
Old versions often access the same data and may miss newer gateway or authorization controls. I run authentication, scope, tenant, object, property, rate, and cache tests across every supported version. A secure v2 cannot protect a vulnerable v1 route.
Q: How would you test a version rollout with database changes?
I create data before, during, and after a mixed deployment, then read and update it with old and new code. I cover queued work, rollback, new enum states, and migration repeatability. The key question is whether both revisions can safely operate on the shared schema during the rollout window.
Common Mistakes
- Confusing the API contract version with the HTTP or OpenAPI Specification version.
- Testing only the newest version and assuming old routes inherit its controls.
- Treating a clean schema diff as proof of behavioral compatibility.
- Updating the accepted baseline automatically to make a breaking diff pass.
- Sending only latest-SDK requests to historical endpoints.
- Ignoring defaults, units, ordering, pagination, and error semantics.
- Allowing conflicting version selectors to fall back silently.
- Comparing full v1 and v2 responses even when differences are intentional.
- Skipping cross-version writes over shared data.
- Adding deprecation headers with invalid formats or inconsistent scope.
- Retiring a route without checking legacy hosts, jobs, callbacks, and rollback paths.
- Logging high-cardinality consumer or resource identifiers as metric labels.
Conclusion
Testing API versioning protects a living set of consumer promises. Combine selector and routing tests, schema analysis, historical request replay, version-specific behavior, cross-version state workflows, security parity, cache checks, migration rehearsal, and standards-based lifecycle signals.
Start by inventorying every supported version and one representative consumer journey for each. Turn that inventory into a CI compatibility report, then add migration and sunset evidence before changing or retiring any contract.
Interview Questions and Answers
What does API versioning testing cover?
It covers version selection, request and response semantics, old-consumer compatibility, shared data, security parity, cache behavior, migration, and lifecycle signals. I treat each live version as a supported contract with an owner and evidence.
How do you determine whether an API change is breaking?
I compare the proposed behavior with supported consumer expectations. I review structural changes, defaults, validation, types, enums, units, status codes, errors, and semantics. Then I replay real consumer operations because a schema diff cannot see every dependency.
What is the value of OpenAPI diffing?
It quickly identifies likely breaking changes in paths, parameters, schemas, responses, and security. I review direction and context rather than accepting the classification blindly. The description must be paired with provider behavior and consumer evidence.
How do you test shared state across v1 and v2?
I create and update through each version, then read through the other where supported. I assert common domain invariants and deliberate representation differences. I focus on lossy mapping, new states, defaults, stale writes, and events.
How do you test conflicting version selectors?
I send combinations such as a v2 path with a v1 header. The service should reject ambiguity or apply one documented precedence rule consistently across the fleet. I also prove no business work occurs before rejection.
How do you validate API deprecation?
If adopted, I validate RFC 9745 Deprecation, a trusted migration link, and RFC 8594 Sunset. I check dates, scope, cache visibility, and unaffected routes. I also rehearse consumer behavior before and after cutoff.
How do you test a mixed-version deployment?
I route requests through old and new application nodes with the same gateway and database. I create data before, during, and after rollout, then exercise reads, writes, jobs, and rollback. Behavior must not depend on which node handles the request.
When can an old version be removed?
Only after the published lifecycle decision and migration evidence are complete. I check public routes, legacy hosts, gateways, jobs, callbacks, documentation, consumer usage, and rollback plans. Post-retirement probes can detect accidental reintroduction.
Frequently Asked Questions
What is API versioning testing?
It verifies that each supported version selects the intended contract and preserves documented consumer behavior. It also covers shared state, security controls, caching, migration, deprecation, and retirement.
How do you test API backward compatibility?
Replay representative historical requests and consumer contract tests against the proposed deployment. Combine them with a specification diff and behavioral assertions for defaults, validation, status codes, errors, ordering, and side effects.
Which API versioning strategy is easiest to test?
Path versions are visible and simple to route, but no strategy removes compatibility risk. Header, media type, query, host, and date-based approaches each need selector, cache, gateway, and ambiguity tests.
Can adding a response field break an API?
It can break strict deserializers or clients with closed models even though tolerant JSON clients usually accept it. Review real consumer behavior and treat schema classification as an input, not final proof.
How should QA test API deprecation?
Verify the scope and format of lifecycle signals, migration documentation, usage monitoring, and unchanged behavior during the support window. Rehearse the post-sunset response with a simulated clock or controlled environment.
What is the difference between Deprecation and Sunset headers?
Deprecation signals that clients should migrate while the resource remains usable. Sunset signals an expected time when the resource may become unavailable. They use different standardized date formats.
Why test old API versions for security?
Old routes often access the same data but may miss newer gateway, authorization, rate, or cache controls. A secure new version cannot compensate for a vulnerable supported old version.