or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

api-versioning.mdasync.mdconfiguration.mdcontent-negotiation.mdcontroller-annotations.mdcore-framework.mdcors.mddata-binding.mdexception-handling.mdflash-attributes.mdfunctional-endpoints.mdi18n.mdindex.mdinterceptors.mdmultipart.mdrequest-binding.mdresource-handling.mdresponse-handling.mduri-building.mdview-resolution.md
tile.json

api-versioning.mddocs/

API Versioning

API versioning support introduced in Spring MVC 7.0 for managing multiple API versions with version extraction from headers, parameters, paths, or media types.

Capabilities

Request Mapping Version Attribute

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();
    }
}

ApiVersionConfigurer

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);
    }
}

Multiple Versioning Strategies

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");
    }
}

Path-Based Versioning

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();
    }
}

Media Type Parameter Versioning

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"
        );
    }
}

Types

ApiVersionResolver

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);
}

ApiVersionParser

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);
}

ApiVersionDeprecationHandler

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 Types

/**
 * 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 {}