Skip to content

API Versioning with path segment strategy does not behave as expected #35404

@ueberfuhr

Description

@ueberfuhr

I currently test the new feature with Spring Web version 7.0.0-M8, and there are multiple issues I had before making it work. First of all, my sample code:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureApiVersioning(@NonNull ApiVersionConfigurer configurer) {
        configurer
                .usePathSegment(1);
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
                .addPathPrefix("/api/{version}", HandlerTypePredicate.forAnnotation(RestController.class));
    }

}

@RestController
@RequestMapping("/hello")
public class MyController {

    @GetMapping(
            version = "1",
            produces = MediaType.TEXT_PLAIN_VALUE
    )
    public String sayHello() {
        return "Hello World";
    }

}

Missing Default

In Spring Boot, convention over configuration is one of the main concepts. But when I specify the version attribute in the controller, the app starts with an error message telling me to configure the versioning strategy. Maybe, there should be a default?

Lack of Documentation

A concrete sample would be nice for the different strategies, whereas header and query params are easier to understand than the path segment strategy. The Javadocs tell me, that there is a semantic versioning with 1.2+ syntax available, but it's not part of the reference documentation

I really had issues with the path seqment strategy, because the hint

Note

When using a path segment, consider configuring a shared path prefix externally in Path Matching options.

was not clear for me. A sample would be really nice here to clarify that this is recommended to add a {version} placeholder. Before getting this, I tried samples without any placeholder, because I thought this path segment would be added automatically to the routing. The second try was to add the placeholder to the @RequestMapping in the controller, which worked for me, but was not a good solution.

Additionally, I tried to use version = "1.0+", but I don't understand why the following samples bring an error response:

# works
GET http://localhost:8080/api/1/hello
GET http://localhost:8080/api/1.0/hello
# doesn't work
GET http://localhost:8080/api/1.0.1/hello
GET http://localhost:8080/api/1.1/hello

Error Responses and Logging

Without the {version} placeholder, I just got a 400 response status, without any message even in the dev mode. The console logs didn't show anything unless I changed the log level to debug. So when trying out, it was hard to detect where the problem is.

I'm not really lucky with the 400, would 404 be correct in case of a missing (or unavailable) version in the path?

Another Question

Would it be possible to get the concrete version injected into my controller's method? With that, we could do switches between versions programmatically instead of routing to different functions. Would be nice, to have this possibility too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions