API Versioning Strategies That Actually Work
BackendAPI Design
Breaking changes are inevitable. API versioning lets you evolve your API without breaking existing clients. Here are the strategies that work in production.
Strategy 1: URL Versioning (Most Common)
GET /api/v1/users
GET /api/v2/users
Pros:
- Clear and explicit
- Easy to route
- Simple to test
Cons:
- Clutters URLs
- Requires duplicate code
Implementation (Spring Boot):
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 {
@GetMapping
public List<UserV1> getUsers() {
return userService.getUsersV1();
}
}
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 {
@GetMapping
public List<UserV2> getUsers() {
return userService.getUsersV2();
}
}
Strategy 2: Header Versioning
GET /api/users
Accept: application/vnd.myapp.v1+json
GET /api/users
Accept: application/vnd.myapp.v2+json
Pros:
- Clean URLs
- RESTful
Cons:
- Harder to test (can’t use browser)
- Less discoverable
Implementation:
@GetMapping(value = "/users", produces = "application/vnd.myapp.v1+json")
public List<UserV1> getUsersV1() {
return userService.getUsersV1();
}
@GetMapping(value = "/users", produces = "application/vnd.myapp.v2+json")
public List<UserV2> getUsersV2() {
return userService.getUsersV2();
}
Strategy 3: Query Parameter
GET /api/users?version=1
GET /api/users?version=2
Pros:
- Simple
- Optional (can default to latest)
Cons:
- Not RESTful
- Easy to forget
Best Practices
1. Deprecation Warnings
@GetMapping("/api/v1/users")
@Deprecated
public ResponseEntity<List<User>> getUsersV1() {
return ResponseEntity.ok()
.header("X-API-Warn", "This version is deprecated. Use /api/v2/users")
.body(users);
}
2. Sunset Header
.header("Sunset", "Sat, 31 Dec 2024 23:59:59 GMT")
3. Changelog Documentation
## v2.0.0 (2024-01-15)
### Breaking Changes
- `user.name` split into `user.firstName` and `user.lastName`
- `POST /users` now requires `email` field
### Migration Guide
```json
// v1
{"name": "John Doe"}
// v2
{"firstName": "John", "lastName": "Doe"}
Conclusion
Recommendation: Use URL versioning for simplicity.
Key Takeaways:
- Version only when breaking changes occur
- Deprecate old versions gradually
- Document migration paths
- Support old versions for 6-12 months
How do you version your APIs? Share your approach!