System Design Cases
API Versioning Strategies
API Versioning Strategies — three side-by-side approaches: URL path versioning (/v1, /v2 in parallel), Stripe-style date-based versioning with per-account pinned date and request/response transformer middleware, and GraphQL @deprecated directive with field usage tracking. Includes ADRs for when to pick each approach plus a deprecation lifecycle scenario covering Sunset/Deprecation HTTP headers, brownouts, and 410 Gone after the grace period.
API versioning: compatibility, routing and deprecation protocols
API versioning — это управление contract compatibility во времени. URI major version, custom header/date version и media-type negotiation имеют routing/cache/tooling trade-offs; универсального победителя нет. Internal API тоже имеет consumers. Версия не заменяет schema discipline, consumer tests, telemetry, migration window и safe retirement.
Что утверждает паттерн — и чего он не гарантирует
- Compatibility is defined by observable client contract, not merely by whether OpenAPI diff calls a change additive.
- Path, header/date and media-type version selectors trade discoverability, caching, routing and tooling; choose and document one policy.
- RFC 9745 Deprecation is an Item Structured Field Date such as @1688169599; RFC 8594 Sunset uses HTTP-date and is a hint, not availability guarantee.
- Internal consumers still require compatibility, ownership, telemetry and migration; “internal” does not authorize silent breaking changes.
Границы и компоненты
| Компонент | Ответственность |
|---|---|
| Pinned API Client | Посылает explicit version и tolerates documented compatible changes. |
| Version Router and Telemetry | Валидирует supported version, routes и считает real usage. |
| v1 Compatibility Contract | Сохраняет обещанные request/response semantics в support window. |
| v2 Incompatible Contract | Содержит intentionally breaking surface и migration mapping. |
| Shared Domain Capability | Не принимает transport/version DTO как domain model. |
| Consumer and Schema Tests | Проверяет known consumers, unknown-field tolerance и behavior. |
| Deprecation and Migration Policy | Публикует dates, docs, owner, replacement и retirement gates. |
| Version Usage Ledger | Хранит client/version/last-seen and telemetry coverage. |
Сценарии
Ship a compatible change cautiously
An optional response field is schema-compatible only if consumer behavior tolerates unknown fields. Contract tests and telemetry check generated/strict clients before broad rollout.
Проверяемый исход: “Additive” is a compatibility hypothesis scoped to real clients, not an absolute guarantee.
Route an explicit API version
Client sends the provider’s documented version selector. Router rejects unknown/retired versions rather than silently guessing and maps v1/v2 DTOs to shared domain semantics.
Проверяемый исход: Routing, caching and observability include the selected version, independent of whether it is in path or header.
Announce deprecation and sunset correctly
Response can send RFC 9745 Deprecation as a Structured Field Date, RFC 8594 Sunset as HTTP-date, and Link rel=deprecation to migration documentation. Sunset is a hint and must not precede deprecation.
Проверяемый исход: Machines parse standards-compliant fields while humans receive migration policy and replacement guidance.
Migrate an incompatible contract
Provider runs v1 and v2 concurrently for a declared window. Client tests/pins v2, provider observes adoption, then retirement returns explicit status rather than mutating v1 in place.
Проверяемый исход: Internal and external consumers follow the same evidence-based migration discipline.
Failure, concurrency и evolution checklist
- Reject unknown/retired versions explicitly and log selected version without sensitive payload.
- Test strict/generated clients, unknown enums/fields and behavioral semantics.
- Provide migration docs/replacement links and measure usage with known telemetry coverage.
- Keep old/new versions concurrently operable for the declared window and rehearse retirement/rollback.
Метрики, units и допущения
- Retirement gate states support end time, last-seen window, known-client coverage and allowed residual traffic ratio.
- Version capacity budget accounts for concurrent v1/v2 traffic and separate cache keys/routes; duplication is measured, not assumed free.
- Sunset timestamp must be later than or equal to deprecation timestamp; clock/format parsing tests use UTC and standards-defined units.
Числа здесь — размерностные формулы или явно помеченные учебные inputs. Паттерн архитектуры сам по себе не задаёт SLA, throughput, latency или fault tolerance.
Связанные темы
[CONCEPT]architecture-decision-records
[CONCEPT]evolutionary-architecture
Первичные источники
- https://www.rfc-editor.org/rfc/rfc9745.html
- https://www.rfc-editor.org/info/rfc8594/
- https://docs.github.com/en/rest/about-the-rest-api/api-versions
- https://google.aip.dev/180
- https://google.aip.dev/185
Scope note
No selector format makes breaking change safe by itself. Compatibility guarantees exist only for the documented surface/window and tested consumers; security/reliability emergency changes may require an explicit exception policy.