springdoc-openapi icon indicating copy to clipboard operation
springdoc-openapi copied to clipboard

Spring Framework 7 - API versioning support

Open csterwa opened this issue 8 months ago • 3 comments

Spring Framework 7 coming in November 2025

With API versioning support getting into Spring Framework 7, there could be an opportunity to generate multiple OpenAPI specifications for each version that is defined for REST API routes in an application. I'd be interested in talking through solution options if there is interest. Some initial thoughts I've had are:

  • Generating a default actuator OpenAPI endpoint but then allow query parameters for different versions
  • Exposed API docs endpoint with query parameters, as well
  • Add a way to show deprecation of API routes in newer version of OpenAPI generated specification

csterwa avatar Apr 28 '25 20:04 csterwa

@csterwa,

Thank your for your initiative.

It would be great to provide out-of-the-box support for API Versioning. Ideally, this would allow us to introspect the versioning metadata provided by Spring Framework 7 and automatically expose those versions as REST endpoints/ routes in the OpenAPI specification.

At the moment, I’m not entirely sure what is feasible with the current implementation, as I’m also waiting for more detailed documentation and clarity around how Spring Framework 7 handles versioning internally. Once that becomes available, we’ll have a better foundation to build on.

In the meantime, if you have a solid understanding of the current versioning support, feel free to:

  • Start drafting representative test cases (e.g., versioned controllers using annotations or URL pathing)
  • Share expected OpenAPI outputs (how each version should be documented and structured)
  • Or propose directly a PR

With those examples, we can begin iterating and exploring how to extend or adapt springdoc-openapi accordingly.

Looking forward to collaborating on this!

bnasslahsen avatar May 03 '25 18:05 bnasslahsen

Sounds great! As Spring Framework 7 API versioning support gets further along and documentation along with solid test cases are put in place we'll update this issue with more details. I'll start drafting some thoughts up in the meantime. Expect some more comments over the summer.

csterwa avatar May 05 '25 21:05 csterwa

Just to mention there is now more detailed documentation. It would be useful to know if there is anything that's perhaps not explained, or could be elaborated on.

rstoyanchev avatar Jun 03 '25 14:06 rstoyanchev

Hi @rstoyanchev,

First off all, thanks you for sharing the docs and the great work on built-in API versioning in Spring Framework 7. After reviewing the documentation and the codebase, I noticed one limitation that makes introspection tricky, especially in WebFlux applications.

Currently, when configuring a versioning strategy via: org.springframework.web.reactive.config.

public ApiVersionConfigurer useRequestHeader(String headerName) {
    this.versionResolvers.add(exchange -> exchange.getRequest().getHeaders().getFirst(headerName));
    return this;
}

public ApiVersionConfigurer useQueryParam(String paramName) {
    this.versionResolvers.add(exchange -> exchange.getRequest().getQueryParams().getFirst(paramName));
    return this;
}

The resolver is added as an anonymous lambda, which makes it nearly impossible at runtime to identify what strategy was configured, or from where the version is being resolved (header vs query param).

🙏 Enhancement Suggestion

Would it be possible to introduce explicit ApiVersionResolver implementations, e.g.:

public class HeaderApiVersionResolver implements ApiVersionResolver { ... }

public class QueryParamApiVersionResolver implements ApiVersionResolver { ... }

Then ApiVersionConfigurer could register these, same as PathApiVersionResolver

public ApiVersionConfigurer useRequestHeader(String headerName) {
    this.versionResolvers.add(new HeaderApiVersionResolver(headerName));
    return this;
}

public ApiVersionConfigurer useQueryParam(String paramName) {
    this.versionResolvers.add(new QueryParamApiVersionResolver(paramName));
    return this;
}

This approach would also be consistent with existing resolvers like PathApiVersionResolver and MediaTypeParamApiVersionResolver, which already have dedicated concrete types.

Having named resolvers for headers and query parameters would enable applications and frameworks to introspect versioning strategies at runtime. This can support advanced tooling — such as API explorers (e.g., springdoc-openapi) — that need to reason about the versioning model. Additionally, making this information accessible could be valuable for monitoring, debugging, and operational visibility.

I’d appreciate your thoughts on this proposal — or if you have an alternative approach in mind that would allow us to determine the versioning strategy at runtime.

bnasslahsen avatar Nov 01 '25 23:11 bnasslahsen

Thanks for the feedback @bnasslahsen. I've created https://github.com/spring-projects/spring-framework/issues/35747 to ensure we have a consistent approach for the ApiVersionResolver hierarchy.

rstoyanchev avatar Nov 03 '25 08:11 rstoyanchev

@bnasslahsen It sounds like you have been getting into the new API versioning capabilities. Some of the user scenarios that I was thinking would be useful would be:

API Developer wants to auto-generate multiple versions of their OpenAPI specification from single Spring application so that they can share each for API discovery

API Consumer wants to view which API version request strategy (i.e. Path, Header or Query Param) to use so that they can target version specific API routes

API Consumer wants to view which API routes are deprecated on a specific API version so that they can change to new API calls

Let me know if you need specific example test cases beyond what is in the Spring Framework source code. I could work on some specific examples.

csterwa avatar Nov 03 '25 20:11 csterwa

Amazing, @rstoyanchev — thanks a lot for your help! 🙌 @csterwa i really appreciate your inputs. Could you please elaborate on the test cases you're expecting to pass? We'll use them as the basis to translate into validation tests for this enhancement request, so we can ensure proper support for the scenarios you've described.

bnasslahsen avatar Nov 03 '25 21:11 bnasslahsen

API Consumer wants to view which API routes are deprecated on a specific API version

Currently, the built-in deprecation handler supports deprecating an entire version only. I've created https://github.com/spring-projects/spring-framework/issues/35750 to build more flexibility into the contract.

rstoyanchev avatar Nov 04 '25 09:11 rstoyanchev

@bnasslahsen I have used Spencer Gibb's SpringOne 2025 repo for API versioning and enhanced it for specifying expected OpenAPI generation based on the use cases above. The README describes the acceptance criteria for each.

https://github.com/csterwa/springone2025-versioning

Let me know if there is anything that needs to be adjusted or if there are details that are not covered.

csterwa avatar Nov 05 '25 17:11 csterwa

@csterwa,

Your description appears to be either incorrect or incomplete. The endpoint /accounts/{id}/statements may result in a single OpenAPI path definition, particularly if you're using a header-based versioning strategy.

Image

It would be helpful if you could include the exact expected OpenAPI specification in your project, similar to how it’s done in the springdoc-openapi tests:

https://github.com/springdoc/springdoc-openapi/tree/main/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0

Additionally, please try to provide specific mappings for each versioning strategy:

  • Versioning Strategy Configuration
  • Corresponding Code
  • Expected OpenAPI 3.1 Specification

This will make it much easier to understand and validate your use cases.

bnasslahsen avatar Nov 08 '25 18:11 bnasslahsen

Does Spring 7 support include Jackson 3?

jan-olaveide avatar Nov 17 '25 21:11 jan-olaveide

Yes it does, see release note. There is also a recent blog post referenced from it.

rstoyanchev avatar Nov 17 '25 21:11 rstoyanchev

I mean for spring-doc. 3.0-RC1 still pulls in Jackson 2 artifacts

jan-olaveide avatar Nov 18 '25 20:11 jan-olaveide

@jan-olaveide,

This is related to swagger-core, until they add support for jackson 2: https://github.com/swagger-api/swagger-core/issues/4991

bnasslahsen avatar Nov 18 '25 20:11 bnasslahsen