How do you version a Web API?
Quick Answer
Pick one scheme and be consistent: URL path (/api/v2/orders) — most visible and cache-friendly; query string (?api-version=2.0); header (api-version: 2.0) — keeps URLs clean; or media type (Accept: application/vnd.myapp.v2+json). Only version on breaking changes; additive changes don't need a new version. In ASP.NET Core the Asp.Versioning library handles all four.
First, I only version on breaking changes — removing a field, changing a type, changing what a value means. Adding a new optional field or a new endpoint shouldn't force a version bump, and clients should be built to ignore fields they don't know. For the scheme, I usually go with the URL path, like /api/v2/orders, because it's the most visible, it's easy to route and cache, and you can hit it straight from a browser. Header or media-type versioning is cleaner in theory but people forget to send the header. Whatever I pick, I support the current and previous version during a deprecation window and communicate a sunset date. In ASP.NET Core the Asp.Versioning package supports all of these.
When to bump the version: removing or renaming a field, changing a type, changing the meaning of a value, removing an endpoint, making an optional field required. Not for adding a new optional field or a new endpoint — clients should tolerate those.
Trade-offs:
- URL path — obvious, easy to route and cache, easy to test in a browser; “pollutes” the URL and implies the resource changed.
- Header / media type — purists' choice, keeps one URL per resource; harder to explore, easy for clients to forget.
- Query string — simple, but mixes versioning with filtering params.
Practices: support N and N-1 during a deprecation window; document the sunset date (Sunset header); keep controllers per version or use API version mapping; share DTO-mapping code so v1 and v2 don't diverge silently.