docs
API versioning support introduced in Spring MVC 7.0 for managing multiple API versions with version extraction from headers, parameters, paths, or media types.
The version attribute on @RequestMapping and its composed annotations (e.g., @GetMapping, @PostMapping) specifies the API version for controllers or handler methods. Introduced in Spring MVC 7.0.
/**
* The version for this mapping.
* <p>A baseline version allows an endpoint to continue to work in subsequent
* versions if it remains compatible. When an incompatible change is made
* eventually, a new controller method for the same endpoint but with a higher
* version takes precedence.
*
* @since 7.0
*/
@RequestMapping(
String version() default ""
)
@GetMapping(String version() default "")
@PostMapping(String version() default "")
@PutMapping(String version() default "")
@DeleteMapping(String version() default "")
@PatchMapping(String version() default "")Usage Example:
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
// Version 1.0 endpoint
@GetMapping(value = "/{id}", version = "1.0")
public User getUserV1(@PathVariable Long id) {
return userService.findById(id);
}
// Version 2.0 endpoint with enhanced response
@GetMapping(value = "/{id}", version = "2.0")
public UserV2 getUserV2(@PathVariable Long id) {
return userService.findByIdV2(id);
}
// Baseline version that works across versions if compatible
@GetMapping(version = "1.0")
public List<User> getAllUsers() {
return userService.findAll();
}
}Configuration for API versioning strategies. Controls how API versions are extracted from requests. Introduced in Spring MVC 7.0.
/**
* Configure API versioning.
*
* @since 7.0
*/
public class ApiVersionConfigurer {
/**
* Add resolver to extract the version from a request header.
*
* @param headerName the header name to check
* @return this configurer for chaining
*/
public ApiVersionConfigurer useRequestHeader(String headerName) {}
/**
* Add resolver to extract the version from a query string parameter.
*
* @param paramName the parameter name to check
* @return this configurer for chaining
*/
public ApiVersionConfigurer useQueryParam(String paramName) {}
/**
* Add resolver to extract the version from a media type parameter found in
* the Accept or Content-Type headers.
*
* @param compatibleMediaType the media type to extract the parameter from with
* the match established via MediaType.isCompatibleWith(MediaType)
* @param paramName the name of the parameter
* @return this configurer for chaining
*/
public ApiVersionConfigurer useMediaTypeParameter(
MediaType compatibleMediaType,
String paramName) {}
/**
* Add resolver to extract the version from a path segment.
* <p>Note that this resolver never returns null, and therefore cannot yield
* to other resolvers.
*
* @param index the index of the path segment to check; e.g. for URL's like
* "/{version}/..." use index 0, for "/api/{version}/..." use index 1
* @return this configurer for chaining
*/
public ApiVersionConfigurer usePathSegment(int index) {}
/**
* Add custom resolvers to resolve the API version.
*
* @param resolvers the resolvers to use
* @return this configurer for chaining
*/
public ApiVersionConfigurer useVersionResolver(ApiVersionResolver... resolvers) {}
/**
* Configure a parser to parse API versions with.
* <p>By default, SemanticApiVersionParser is used.
*
* @param versionParser the parser to use
* @return this configurer for chaining
*/
public ApiVersionConfigurer setVersionParser(ApiVersionParser<?> versionParser) {}
/**
* Whether requests are required to have an API version. When set to true,
* MissingApiVersionException is raised, resulting in a 400 response if the
* request doesn't have an API version. When set to false, a request without
* a version is considered to accept any version.
* <p>By default, this is set to true when API versioning is enabled by
* adding at least one ApiVersionResolver. When a default version is also
* set, this is automatically set to false.
*
* @param required whether an API version is required
* @return this configurer for chaining
*/
public ApiVersionConfigurer setVersionRequired(boolean required) {}
/**
* Configure a default version to assign to requests that don't specify one.
*
* @param defaultVersion the default version to use
* @return this configurer for chaining
*/
public ApiVersionConfigurer setDefaultVersion(String defaultVersion) {}
/**
* Add to the list of supported versions to check against before raising
* InvalidApiVersionException for unknown versions.
* <p>By default, actual version values that appear in request mappings are
* used for validation. Therefore, use of this method is optional. However,
* if you prefer to use explicitly configured, supported versions only, then
* set detectSupportedVersions to false.
* <p>Note that the initial API version, if not explicitly declared in any
* request mappings, may need to be declared here instead as a supported version.
*
* @param versions supported versions to add
* @return this configurer for chaining
*/
public ApiVersionConfigurer addSupportedVersions(String... versions) {}
/**
* Whether to use versions from mappings for supported version validation.
* <p>By default, this is true in which case mapped versions are considered
* supported versions. Set this to false if you want to use only explicitly
* configured supported versions.
*
* @param detect whether to use detected versions for validation
* @return this configurer for chaining
*/
public ApiVersionConfigurer detectSupportedVersions(boolean detect) {}
/**
* Provide a Predicate to perform supported version checks with, in effect
* taking over the supported version check and superseding addSupportedVersions
* and detectSupportedVersions.
*
* @param predicate the predicate to use
*/
public void setSupportedVersionPredicate(Predicate<Comparable<?>> predicate) {}
/**
* Configure a handler to add handling for requests with a deprecated API
* version. Typically, this involves sending hints and information about
* the deprecation in response headers.
*
* @param handler the handler to use
* @return this configurer for chaining
*/
public ApiVersionConfigurer setDeprecationHandler(ApiVersionDeprecationHandler handler) {}
}Usage Example:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
// Extract version from header
configurer.useRequestHeader("X-API-Version");
// Or extract from query parameter
// configurer.useQueryParam("version");
// Or extract from path segment (index 0 for "/{version}/...")
// configurer.usePathSegment(0);
// Or extract from media type parameter
// configurer.useMediaTypeParameter(
// MediaType.parseMediaType("application/vnd.myapp.*"),
// "version"
// );
// Configure additional options
configurer
.setDefaultVersion("1.0")
.addSupportedVersions("1.0", "1.1", "2.0")
.setVersionRequired(false);
}
}You can combine multiple version resolution strategies. The first resolver that finds a version wins.
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
// Try header first, fall back to query parameter
configurer
.useRequestHeader("X-API-Version")
.useQueryParam("version")
.setDefaultVersion("1.0");
}
}For path-based versioning where the version appears in the URL path:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
// Extract version from first path segment
// Matches URLs like: /v1/users, /v2/users
configurer.usePathSegment(0);
}
}
@RestController
public class UserController {
// Handles /v1/users
@GetMapping(value = "/{version}/users", version = "1")
public List<User> getUsersV1() {
return userService.findAllV1();
}
// Handles /v2/users
@GetMapping(value = "/{version}/users", version = "2")
public List<UserV2> getUsersV2() {
return userService.findAllV2();
}
}Extract version from Accept or Content-Type header media type parameters:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
// Extract version parameter from media types like:
// application/vnd.myapp.v1+json
// application/vnd.myapp.v2+json
configurer.useMediaTypeParameter(
MediaType.parseMediaType("application/vnd.myapp.*"),
"version"
);
}
}Strategy interface for extracting API version from requests.
/**
* Strategy to extract an API version from a request.
*
* @since 7.0
*/
public interface ApiVersionResolver {
/**
* Resolve the API version for the given request.
*
* @param request the current request
* @return the resolved version string, or null if not found
*/
String resolveVersion(HttpServletRequest request);
}Parser interface for converting version strings to comparable version objects.
/**
* Strategy to parse API version strings.
*
* @param <T> the type of comparable version object produced
* @since 7.0
*/
public interface ApiVersionParser<T extends Comparable<T>> {
/**
* Parse a version string.
*
* @param version the version string to parse
* @return the parsed comparable version
*/
T parse(String version);
}Handler for deprecated API versions that can add response headers or perform other actions.
/**
* Strategy to handle requests with deprecated API versions.
*
* @since 7.0
*/
public interface ApiVersionDeprecationHandler {
/**
* Handle a request with a deprecated API version.
*
* @param version the deprecated version
* @param request the current request
* @param response the current response
*/
void handleDeprecatedVersion(
Comparable<?> version,
HttpServletRequest request,
HttpServletResponse response);
}/**
* Exception raised when a request does not contain an API version
* but one is required.
*
* @since 7.0
*/
public class MissingApiVersionException extends ServletException {}
/**
* Exception raised when a request contains an invalid or unsupported
* API version.
*
* @since 7.0
*/
public class InvalidApiVersionException extends ServletException {}