Mastering API Versioning in Spring Framework 7.0: Strategies and Code Samples
This article explains why API version control is essential for modern web services, outlines common versioning strategies such as URI, header, query‑parameter and content negotiation, and demonstrates how Spring Framework 7.0 natively supports versioned routing on both server and client sides with practical code examples.
Importance of API Version Control
API version control lets developers introduce new features, fix bugs, or change data structures while preserving backward compatibility. Common strategies include:
URI versioning : include the version in the URL path, e.g.,
/api/v1/users.
Header versioning : specify the version via a request header such as
Accept: application/vnd.company.app-v1+json.
Query‑parameter versioning : pass the version as a query parameter, e.g.,
/api/users?version=1.
Content negotiation : determine the version based on the media type in the
Acceptheader.
Spring 7.0 API Version Control
Spring Framework 7.0 adds native support for API versioning. By adding a
versionattribute to the
@RequestMappingannotation, requests are routed to the appropriate controller method based on the requested version.
Implementation Details
Developers can specify a version range in
@RequestMapping. Spring resolves the version from the request and dispatches to the matching method. Versions can be parsed from:
Request URL path : e.g.,
/api/v1/usersor
/api/v2/users.
Request header : e.g.,
Accept: application/vnd.company.app-v1+json.
Custom sources : developers may configure additional resolvers.
Example controller demonstrating two API versions:
<code>import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping(value = "/api/users", version = "1.0")
public ResponseEntity<List<UserV1>> getUsersV1() {
// implementation for version 1.0
List<UserV1> users = fetchUsersV1();
return ResponseEntity.ok(users);
}
@RequestMapping(value = "/api/users", version = "2.0")
public ResponseEntity<List<UserV2>> getUsersV2() {
// implementation for version 2.0
List<UserV2> users = fetchUsersV2();
return ResponseEntity.ok(users);
}
}
</code>In this example the
/api/usersendpoint calls different methods depending on whether the request specifies version
1.0or
2.0. The version can be supplied via the URL path (e.g.,
/api/v1/users) or a request header.
Client API Version Control
Spring 7.0 also enhances client‑side versioning. When using
WebClientor similar tools, developers can set the desired API version in the request headers to ensure the client interacts with the correct version.
Client Example
Using
WebClientto request version 1.0:
<code>import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class UserClient {
private final WebClient webClient;
public UserClient(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("http://example.com").build();
}
public Mono<List<User>> getUsersV1() {
return webClient.get()
.uri("/api/users")
.accept(MediaType.valueOf("application/vnd.company.app-v1+json"))
.retrieve()
.bodyToMono(List.class);
}
}
</code>The client sets the
Acceptheader to
application/vnd.company.app-v1+json, guaranteeing that the server returns data for API version 1.0.
API Version Control Source Analysis
Spring Framework 7.0 implements API versioning through several core classes:
ApiVersionResolver Interface
This functional interface defines a contract for extracting a version string from a request.
<code>@FunctionalInterface
public interface ApiVersionResolver {
/**
* Resolve the version from the given exchange.
* @param exchange the current exchange
* @return the version value, or null if not found
*/
@Nullable
String resolveVersion(ServerWebExchange exchange);
}
</code>PathApiVersionResolver Implementation
Extracts the version from a specific segment of the URL path.
<code>public class PathApiVersionResolver implements ApiVersionResolver {
private final int pathSegmentIndex;
/**
* Create a resolver instance.
* @param pathSegmentIndex the index of the path segment containing the API version
*/
public PathApiVersionResolver(int pathSegmentIndex) {
Assert.isTrue(pathSegmentIndex >= 0, "'pathSegmentIndex' must be >= 0");
this.pathSegmentIndex = pathSegmentIndex;
}
@Override
@Nullable
public String resolveVersion(ServerWebExchange exchange) {
int i = 0;
for (PathContainer.Element e : exchange.getRequest().getPath().pathWithinApplication().elements()) {
if (e instanceof PathContainer.PathSegment && i++ == this.pathSegmentIndex) {
return e.value();
}
}
return null;
}
}
</code>DefaultApiVersionStrategy Class
Provides the default strategy for parsing, validating, and supplying a default version.
<code>public class DefaultApiVersionStrategy implements ApiVersionStrategy {
@Override
@Nullable
public Comparable<?> parseVersion(ServerWebExchange exchange) {
// implementation omitted for brevity
}
@Override
@Nullable
public Comparable<?> findDefaultVersion() {
return this.defaultVersion;
}
@Override
public boolean isVersionRequired() {
return this.versionRequired;
}
@Override
public void validateVersion(@Nullable Comparable<?> requestVersion, ServerWebExchange exchange)
throws MissingApiVersionException, InvalidApiVersionException {
// implementation omitted for brevity
}
}
</code>VersionRequestCondition Class
Acts as a request‑mapping condition that matches incoming requests to the appropriate versioned handler.
<code>public class VersionRequestCondition implements RequestCondition<VersionRequestCondition> {
@Override
@Nullable
public VersionRequestCondition getMatchingCondition(ServerWebExchange exchange) {
Comparable<?> requestVersion = this.versionStrategy.parseVersion(exchange);
// matching logic omitted for brevity
return this;
}
}
</code>Conclusion
Spring Framework 7.0’s API version control offers a flexible, extensible mechanism that lets developers manage API versions in a standardized way. Core components such as
ApiVersionResolver,
DefaultApiVersionStrategy, and
VersionRequestConditionwork together to resolve, validate, and route versioned requests, supporting common strategies while allowing custom implementations for specific business needs.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.