API Versioning in Spring Boot Using HTTP Headers — Clean Header-Based Approach
API Versioning in Spring Boot Using HTTP Headers — A Clean & Elegant Approach
Breaking changes in APIs break clients — mobile apps, frontends and partner systems. API versioning is essential for any long-lived service.
In this post you’ll learn how to implement header-based API versioning in Spring Boot using a dedicated header like API-Version.
I’ll explain the configuration, show controller examples, compare alternatives, and include Postman test samples.
What does this configuration mean?
Add this property to application.properties or application.yml:
spring.mvc.apiversion.use.header = API-Version
This tells Spring to read the HTTP header named API-Version on incoming requests. Based on that header value (for example 1 or 2), Spring will route the request to the controller method annotated for that version.
Versioned controller example
Write multiple handler methods with the same path but different version attributes:
// V1
@GetMapping(value = "/products/{id}", version = "1")
public ProductResponseV1 getProductV1(@PathVariable Long id) {
return new ProductResponseV1("Basic product information");
}
// V2
@GetMapping(value = "/products/{id}", version = "2")
public ProductResponseV2 getProductV2(@PathVariable Long id) {
return new ProductResponseV2("Advanced details", "newField");
}
Both methods map to /products/{id}. Which one runs depends on the value in the request header:
API-Version: 1→getProductV1()API-Version: 2→getProductV2()
version on mapping annotations. If you don’t have such built-in support, you can implement a custom HandlerMapping or use content negotiation/filter that routes using a header.
Why header-based versioning?
- Clean URLs: Your URLs stay tidy:
/products/10rather than/v2/products/10. - Backward compatibility: Old clients continue sending
API-Version: 1, new clients useAPI-Version: 2. - Explicit: Clients specify which API version they need via a single header.
- Good for microservices: Each service can support multiple versions without changing endpoints.
How to test (Postman / curl)
Postman: Add a request header named API-Version.
GET /products/10
Header: API-Version = 1
curl example:
curl -H "API-Version: 2" "https://api.example.com/products/10"
Comparison with other versioning methods
| Method | Example | Pros / Cons |
|---|---|---|
| URL versioning | /v1/products/10 |
Simple but pollutes URLs. Easy for routing & caching. |
| Query param | /products/10?version=1 |
Works, but not semantically clean; may cause caching oddities. |
| Content negotiation | Accept: application/vnd.app.v1+json |
Powerful but more complex for clients to implement. |
| Header versioning | API-Version: 2 |
Clean URLs, explicit client choice — good balance for many APIs. |
Practical tips & best practices
- Document versions clearly in your API docs and changelog.
- Provide a default behavior if header is missing (e.g., default to v1) and document it.
- Deprecate old versions responsibly — announce and maintain compatibility windows.
- Keep DTOs separated per version (ProductResponseV1, ProductResponseV2) to avoid accidental breaking changes.
- Consider using feature flags if differences are small and you want gradual rollout.
When header-versioning might not be suitable
If you have public endpoints that must be crawlable or extremely cache-friendly (CDNs often cache by URL, not header), URL-based versioning might be a better fit. Also, some simple clients (or third-party integrations) that don’t let you set custom headers may find header-based versioning inconvenient.
Comments
Post a Comment