-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
I am trying to understand the new API Versioning feature introduced in Spring 7 and seems like something is not right. According to the spring documentation, if versioning is enabled and no version attribute is specified in the handler method, then it is considered (unversioned) as a match to any (supported) version.
Below is from Spring Reference Doc
Once API versioning is enabled, you can begin to map requests with versions. The @RequestMapping version attribute supports the following:
No value — matches any version
Fixed version ("1.2") — matches the given version only
Baseline version ("1.2+") — matches the given version and above
Check the attached controller and the properties file.
SampleController.java
package com.example;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/{version}/data")
public class SampleController {
@GetMapping
public String unversioned() {
return "unversioned";
}
@GetMapping(version = "v1.0.0")
public String version1() {
return "version 1";
}
}application.properties
trace = true
spring.mvc.apiversion.use.path-segment = 1
// added this just to explain the behaviour
spring.mvc.apiversion.supported = 100, 200I have implemented a URI path based versioning with two handler methods. One with a specific version and the other without any version (no version attribute specified).
So I expect the below requests should behave as follows:
Request-1:
http://localhost:8080/api/v1/data --> should return "version 1", as it is an exact match
Request-2:
http://localhost:8080/api/v100/data --> should return "unversioned", as there is no exact version match, and the unversioned() method should be called but it is not, instead it returns a 400 Bad Request.
Response: There was an unexpected error (type=Bad Request, status=400).
I did a little bit of debugging and found that the lookupHandlerMethod() method in the AbstractHandlerMethodMapping.java is getting two matches for the request GET /api/v100/data and selecting the handler method with version attribute specified as the best match which is not correct.
Matches:
- {GET [/api/{version}/data]} --> should consider this as best match
- {GET [/api/{version}/data], version [v1.0.0]} --> this is not the best match but the framework picks this as best match.
Console log:
2025-12-29T16:34:36.750+05:30 TRACE 88093 --- [spring-boot-api-versioning-101] [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : GET "/api/v100/data", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2025-12-29T16:34:36.752+05:30 TRACE 88093 --- [spring-boot-api-versioning-101] [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : 2 matching mappings: [{GET [/api/{version}/data], version [v1.0.0]}, {GET [/api/{version}/data]}]
2025-12-29T16:34:36.752+05:30 WARN 88093 --- [spring-boot-api-versioning-101] [nio-8080-exec-4] .w.s.m.a.ResponseStatusExceptionResolver : Resolved [org.springframework.web.accept.NotAcceptableApiVersionException: 400 BAD_REQUEST "Invalid API version: '100.0.0'."]
