Implementing application versioning in a Spring Boot REST API is crucial for supporting backward compatibility when your API evolves. There are several strategies to version a Spring Boot API, and the method you choose depends on your design goals and client needs.
Common Strategies for API Versioning
1. URI Path Versioning (Recommended)
Most widely used method: Version is part of the URL path like /v1/..., /v2/...
Example:
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 {
@GetMapping
public List<String> getUsers() {
return List.of("User1", "User2");
}
}
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 {
@GetMapping
public List<String> getUsers() {
return List.of("User1", "User2", "User3");
}
}
Pros:
- Easy to test and debug
- Cache-friendly
- Follows REST best practices
Cons:
- Duplicates endpoints if many versions exist
2. Request Parameter Versioning
Use a query parameter to specify version:
Example: /api/users?version=1
Implementation:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping(params = "version=1")
public String getV1() {
return "User API V1";
}
@GetMapping(params = "version=2")
public String getV2() {
return "User API V2";
}
}
Pros:
- Single URL, cleaner routing logic
- Allows default versioning
Cons:
- Not very RESTful
- More logic in controllers to handle parameters
3. Header Versioning
Clients pass version via custom headers like:X-API-VERSION: 1
Implementation:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping(headers = "X-API-VERSION=1")
public String getV1() {
return "User API V1";
}
@GetMapping(headers = "X-API-VERSION=2")
public String getV2() {
return "User API V2";
}
}
Pros:
- Keeps URLs clean
- Clients can dynamically switch versions via headers
Cons:
- Not easily cacheable
- More complex for testing/debugging
4. Content Negotiation (Media Type Versioning)
Uses the Accept header to specify version:
Accept Header Example:Accept: application/vnd.myapp.v1+json
Implementation:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping(produces = "application/vnd.myapp.v1+json")
public String getV1() {
return "User API V1";
}
@GetMapping(produces = "application/vnd.myapp.v2+json")
public String getV2() {
return "User API V2";
}
}
Pros:
- Clean URL
- Flexible for complex content negotiation
Cons:
- Difficult for clients to set headers correctly
- Hard to test via browser or tools like Postman
Versioning Best Practices
- Start with URI versioning for simplicity and clarity.
- Keep each version isolated with its own controller or package.
- Deprecate old versions gracefully and document timelines.
- Provide changelogs and API documentation for each version using tools like Swagger (SpringDoc).
- If you use Swagger/OpenAPI, configure versioned docs like
/v1/api-docs.
Example Project Structure (URI Versioning)
src
└── main
└── java
└── com.example.demo
├── controller
│ ├── v1
│ │ └── UserControllerV1.java
│ └── v2
│ └── UserControllerV2.java
