# 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.