Add openapi-versioning: springdoc-openapi 3.1.1 vs Spring Framework 7 API versioning
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
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# The fix: one GroupedOpenApi per version
|
||||
|
||||
Full transcript: [docs/output/05-grouped-openapi-fix.txt](output/05-grouped-openapi-fix.txt), from
|
||||
`OpenApiVersioningTest#c_groupedOpenApiCustomizerCollapsesToOneCleanSchemaPerVersion`.
|
||||
|
||||
[`VersionedOpenApiConfig`](../src/main/java/com/ankurm/openapiversioning/config/VersionedOpenApiConfig.java)
|
||||
registers three `GroupedOpenApi` beans — one per supported version — each scoped to
|
||||
`/accounts/**` and each carrying an `OpenApiCustomizer` that collapses the merged `oneOf` response
|
||||
from the previous chapter down to the one schema that version's clients actually receive, fixes
|
||||
`operationId` and `summary` to match, and drops the now-meaningless `API-Version` header:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public GroupedOpenApi accountsV1Group() {
|
||||
return groupFor("accounts-v1", "1");
|
||||
}
|
||||
|
||||
private GroupedOpenApi groupFor(String groupName, String version) {
|
||||
VersionSpec spec = SPECS.get(version);
|
||||
return GroupedOpenApi.builder()
|
||||
.group(groupName)
|
||||
.pathsToMatch("/accounts/**")
|
||||
.addOpenApiCustomizer(collapseToSingleVersion(spec))
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
Each group is served at `/v3/api-docs/{group}` (springdoc's own convention — no extra wiring
|
||||
needed). Result, all three fetched from the same running instance:
|
||||
|
||||
```
|
||||
GET /v3/api-docs/accounts-v1 -> operationId=getAccountV1, schema=AccountV1, params=[id]
|
||||
GET /v3/api-docs/accounts-v1.1 -> operationId=getAccountV1Point1Plus, schema=AccountV1Point1, params=[id]
|
||||
GET /v3/api-docs/accounts-v2 -> operationId=getAccountV2, schema=AccountV2, params=[id]
|
||||
```
|
||||
|
||||
Each is a clean, single-schema operation — feed any one of these three documents into
|
||||
openapi-generator and you get one method whose declared response type is actually what that
|
||||
version's clients receive, not a `oneOf` of three.
|
||||
|
||||
**The default, ungrouped `/v3/api-docs` is untouched** — confirmed by re-fetching it inside the
|
||||
same test, immediately after fetching all three groups, and it still shows the exact `oneOf` merge
|
||||
from the previous chapter. `GroupedOpenApi`'s customizer runs against a document scoped to that
|
||||
group's own build, not the shared default document, so adding version-specific groups is additive:
|
||||
existing tooling pointed at the plain `/v3/api-docs` (or Swagger UI's default view) keeps working
|
||||
exactly as it did before, while `/v3/api-docs/accounts-v2` becomes a new, additional,
|
||||
clean-per-version resource for anyone who wants one — a generated TypeScript client for your v2
|
||||
mobile app, say, without also generating types for the v1 shape it will never receive.
|
||||
|
||||
See [the previous chapter](03-why-a-hand-maintained-map.md) for why the version→schema mapping
|
||||
this customizer applies is a small hand-written `Map`, not something derived automatically from
|
||||
the running handler mappings — that's a real limitation of the public springdoc customizer API,
|
||||
not a shortcut taken for the sake of the demo.
|
||||
|
||||
## Swagger UI
|
||||
|
||||
With three additional groups registered, `/swagger-ui.html` grows a group selector (`default`,
|
||||
`accounts-v1`, `accounts-v1.1`, `accounts-v2`) — switching between them re-fetches the
|
||||
corresponding `/v3/api-docs/{group}` document, so the same collapsed, single-schema view is what a
|
||||
human reading the UI sees too, not just API clients hitting the JSON directly.
|
||||
Reference in New Issue
Block a user