Companion module for "springdoc-openapi with Spring Boot 4.1: Generating, Customising and Versioning Your API Spec". Reuses the ApiVersionConfigurer setup from the versioning-mechanics companion project and tests what springdoc-openapi 3.1.1 actually generates for a path with multiple version-scoped handlers: a default oneOf-merged operation with an arbitrary operationId, a working GroupedOpenApi + OpenApiCustomizer fix that collapses it to one clean schema per version, and a check of the officially-versioning-supported functional-endpoint path (springdoc v3.0.2's "Add support for Spring Framework API Versioning with Functional Endpoints"), which turns out to document only one of two registered versions rather than either version separately. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01M1uZDXWkY1MnTfQgt4HMeQ
openapi-versioning
Companion code for springdoc-openapi with Spring Boot 4.1: Generating, Customising and Versioning Your API Spec on ankurm.com.
Reuses the exact ApiVersionConfigurer setup from the companion project for Spring Framework 7
API Versioning: The Complete Guide
and asks one question on top of it: once springdoc-openapi 3.1.1 is added, what does it actually
generate for a path with multiple version-scoped handlers — and how do you get a clean,
per-version spec out of it?
Tested with: Spring Boot 4.1.1 / Spring Framework 7.0.9 / springdoc-openapi 3.1.1 / JDK 25 (Temurin 25.0.4.1+1).
Quickstart
mvn test # runs everything, regenerates docs/output/
mvn spring-boot:run # then, in another shell:
curl http://localhost:8080/v3/api-docs # the merged oneOf (default)
curl http://localhost:8080/v3/api-docs/accounts-v2 # the collapsed, clean v2-only spec
open http://localhost:8080/swagger-ui.html # group selector: default / accounts-v1 / accounts-v1.1 / accounts-v2
Where things are
| Versions and setup | docs/01-versions-and-setup.md |
| What springdoc actually generates for a versioned path | docs/02-what-springdoc-actually-generates.md |
| Why the fix's version→schema map is hand-maintained | docs/03-why-a-hand-maintained-map.md |
| The functional-endpoint path: officially supported, and worse | docs/04-the-functional-endpoint-path.md |
| The fix: one GroupedOpenApi per version | docs/05-the-grouped-openapi-fix.md |
| Known issues, checked directly | docs/06-known-issues.md |
Captured output
Every figure quoted in the article is one of these files, regenerated by mvn test:
| File | What it shows |
|---|---|
| docs/output/00-versions.txt | Exact resolved versions, including Maven Central metadata for springdoc 3.1.1 |
| docs/output/01-versioned-runtime-behaviour.txt | The three /accounts/{id} versions serving their real, distinct shapes |
| docs/output/02-what-springdoc-actually-generates.txt | The default /v3/api-docs merging all three versions into one oneOf operation |
| docs/output/05-grouped-openapi-fix.txt | Three GroupedOpenApi groups, each collapsed to one clean schema |
| docs/output/06-functional-endpoint-path.txt | The officially-versioning-supported functional-endpoint path silently documenting only one of two registered versions |
Source layout
web/— the annotated@GetMapping(version = ...)AccountControllerand its three response records.functional/— theRouterFunction-basedWidgetHandler/WidgetRouterConfig, Framework 7's officially-versioning-supported alternative.config/WebConfig.java— theApiVersionConfigurersetup, unchanged from the versioning-mechanics companion project.config/VersionedOpenApiConfig.java— the three per-versionGroupedOpenApibeans and theOpenApiCustomizerthat makes them clean.