What is a breaking change in an API and why must it be versioned?
Breaking vs non-breaking changes: Breaking: remove a field, rename a field, change a field's type (string → integer), change HTTP method for an endpoint, change response status code meaning, change pagination format, add a new required request field. Non-breaking (backward-compatible): add new optional field to response, add new optional request parameter with a default, add a new endpoint, add a new enum value (debated — old clients may not handle unknown values), change error message text (if clients don't parse it). API contract principle: clients depend on what you promise; don't break that promise without versioning. Postel's Law: be conservative in what you send, liberal in what you accept.
2 / 5
What are the main API versioning strategies and their trade-offs?
Versioning strategies: URL path (/v1/, /v2/): most common. Visible in URL, easy to route at gateway, easy to test in browser. Breaks REST purity (resource identifier includes version). Header (Accept: application/vnd.api+json;version=2 or API-Version: 2): cleaner URLs, HTTP-correct, harder to test, less discoverable. Query parameter (?version=2): easy browser testing, less RESTful. Good for simple public APIs. Content negotiation (Accept: application/vnd.company.v2+json): most REST-correct, most complex. Sunset header (RFC 8594): Sunset: Sat, 31 Dec 2025 00:00:00 GMT. Deprecation header: Deprecation: true. Log which clients use deprecated versions.
3 / 5
What is the expand-contract pattern for API migration?
Expand-contract (parallel change): phase 1 — Expand: add new field/behavior alongside old. Both old and new format available. No consumer changes required yet. Phase 2 — Migrate: update all consumers to use new field/endpoint. Monitor until all consumers migrated. Phase 3 — Contract: remove old field/endpoint. Safe because all consumers already migrated. Example: renaming a field from "phone" to "phone_number". Expand: add "phone_number" field (copy of "phone"). Migrate: update each consumer to read "phone_number". Contract: remove "phone" field. Applied to: field renames, endpoint URL changes, request format changes, database schema changes. Enables truly zero-downtime migrations for internal APIs.
4 / 5
What is Semantic Versioning (semver) and how does it apply to API design?
Semantic Versioning (semver 2.0.0): MAJOR.MINOR.PATCH. MAJOR: increment when you make breaking changes. MINOR: increment when you add functionality in a backward-compatible manner. PATCH: increment for backward-compatible bug fixes. Pre-release: 1.0.0-alpha.1. Consumer contract: if you depend on 1.x.x, any 1.y.z is safe (y >= current minor, z >= current patch). 2.0.0 may break you. API semver: not all APIs use semver explicitly. URL versioning uses only major (/v1/, /v2/). Library SDKs use full semver. Lock files (package-lock.json, Gemfile.lock, go.sum): pin exact versions including patch, reproducible builds. Dependency ranges: ^1.2.3 = >=1.2.3 <2.0.0 (compatible with minor/patch updates). Renovate/Dependabot: automate minor/patch updates.
5 / 5
What is a sunset date and what should API providers do to enforce it?
Sunset date: RFC 8594 defines the Sunset HTTP response header: Sunset: Sat, 31 Dec 2025 23:59:59 GMT. API providers should: (1) announce sunset date at minimum 6-12 months in advance (longer for external/public APIs), (2) add Deprecation and Sunset headers to every response on deprecated endpoints, (3) log which clients are still calling the deprecated API with their identifiers, (4) send email/Slack notifications to identified consumer teams, (5) apply graduated pressure (throttling, rate limiting deprecated endpoints before removal), (6) enforce the sunset date firmly — soft deadlines extend indefinitely. After sunset: return 410 Gone (not 404) to indicate permanent removal. 410 tells clients to stop retrying, unlike 404 which might indicate a temporary routing issue.