Spring Framework 7 (Spring Boot 4) API Versioning feature not behaves as expected

4 weeks ago 16
ARTICLE AD BOX

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.

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, 200

I 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'."]

image-1

image-2

Read Entire Article