Skip to content

Open API: Use Microsoft.AspNetCore.OpenApi for Open API document generation#21058

Merged
lauraneto merged 118 commits into
v18/devfrom
v18/feature/microsoft-open-api-document-generation
Apr 30, 2026
Merged

Open API: Use Microsoft.AspNetCore.OpenApi for Open API document generation#21058
lauraneto merged 118 commits into
v18/devfrom
v18/feature/microsoft-open-api-document-generation

Conversation

@lauraneto

@lauraneto lauraneto commented Dec 4, 2025

Copy link
Copy Markdown
Contributor

Summary

Migrates from Swashbuckle.AspNetCore to Microsoft's native Microsoft.AspNetCore.OpenApi package for OpenAPI document generation.

Biggest changes

  • Installed Microsoft.AspNetCore.OpenApi and Swashbuckle.AspNetCore.SwaggerUI and uninstalled Swashbuckle.AspNetCore - keeping the swagger UI for now.
  • A lot of renaming from swagger -> openapi and filter -> transformer, including document and UI routes.
  • Added a shared ConfigureUmbracoOpenApiOptionsBase class from which our APIs (Default, Management and Delivery) extend from, which contains shared configuration/transformers.
  • With Swashbuckle, filters applied to all documents. That is not the case anymore, so when you want to add a transformer/filter, you need to configure it per API. This means that our filtes/transformers won't apply to consumer's documents anymore, unless they explicitly reference them. Due to this I removed the following, as these seemed to have been introduced to avoid making unintentional changes to consumer's custom documents.
    • IOperationIdHandler
    • ISchemaIdHandler
    • RemoveSecuritySchemesDocumentFilter
  • Copied the named Mvc Json Options per API to the Http Json Options, which are the ones used by the Open API generator.
    • ISubTypesSelector and EnumSchemaFilter have been removed as they are no longer needed due to the correct Json Serializer options being used
    • Hack: The Microsoft Open API uses the default Http JsonOptions to generate the Open API documents, it doesn't allow for configuring different JsonOptions per document, as we have for our APIs. As such, and due to the fact that they tried making almost everything they can internal, there is a hack in ReplaceOpenApiSchemaService to replace the registered service, for each API, with one that uses their corresponding settings.
  • Removed open api availability and route configuration from the SwaggerRouteTemplatePipelineFilter and introduced UmbracoOpenApiOptions options, making it easier to configure
  • Draft version of the documentation changes: umbraco/UmbracoDocs@main...cms/v18/microsoft-open-api-docs

What's New

  • UmbracoOpenApiOptions - Configure OpenAPI document routes and UI
  • ExcludeFromDefaultOpenApiDocumentAttribute - Exclude endpoints from the default OpenAPI document
  • UmbracoSchemaIdGenerator - Static class for generating schema IDs (replaces handler interfaces)
  • UmbracoOperationIdTransformer - Public transformer for customizing operation IDs
  • AddBackofficeSecurityRequirements() - Extension method on OpenApiOptions to easily secure custom Management APIs
  • AddDeliveryApiOpenApiMemberAuthentication() - Extension method on IServiceCollection to enable member authentication in the Delivery API OpenAPI document
  • AddOpenApiDocumentToUi() - Extension method to add OpenAPI documents to the UI dropdown, respecting configured route templates
  • Pipeline filter hooks - OnPreMapEndpoints and OnPostMapEndpoints methods on IUmbracoPipelineFilter

Breaking Changes

Type Changes

Change Old New
Removed ISubTypesHandler, ISubTypesSelector, SubTypesHandler, SubTypesSelector JSON discriminator configuration in JsonSerializerOptions
Removed ISchemaIdHandler, ISchemaIdSelector, SchemaIdHandler, SchemaIdSelector Static UmbracoSchemaIdGenerator class
Removed IOperationIdHandler, IOperationIdSelector, OperationIdHandler, OperationIdSelector No longer needed - transformers scoped per-document
Removed IDocumentInclusionSelector, DocumentInclusionSelector No longer needed
Removed ConfigureUmbracoSwaggerGenOptions ConfigureUmbracoOpenApiOptionsBase
Removed EnumSchemaFilter JSON options
Removed MimeTypeDocumentFilter MimeTypesTransformer
Removed RemoveSecuritySchemesDocumentFilter No longer needed
Removed BackOfficeSecurityRequirementsOperationFilterBase AddBackofficeSecurityRequirements() extension method
Removed RequireNonNullablePropertiesSchemaFilter RequireNonNullablePropertiesSchemaTransformer
Removed SwaggerRouteTemplatePipelineFilter UmbracoOpenApiOptions for route/availability configuration
Removed ConfigureUmbracoMemberAuthenticationDeliveryApiSwaggerGenOptions AddDeliveryApiOpenApiMemberAuthentication() extension method
Renamed ConfigureUmbracoDeliveryApiSwaggerGenOptions ConfigureUmbracoDeliveryApiOpenApiOptions
Renamed ConfigureUmbracoManagementApiSwaggerGenOptions ConfigureUmbracoManagementApiOpenApiOptions

Several internal types were also removed/replaced (e.g., NotificationHeaderFilterNotificationHeaderTransformer).

URL Changes

Before After
/umbraco/swagger/{documentName}/swagger.json /umbraco/openapi/{documentName}.json
/umbraco/swagger/ /umbraco/openapi/

The new paths can be customized via UmbracoOpenApiOptions.RouteTemplate and UmbracoOpenApiOptions.UiRoutePrefix.

Note: The OAuth client ID for the OpenAPI UI remains umbraco-swagger for backwards compatibility with existing database registrations in umbracoOpenIddictApplications.

OpenAPI Document Changes

These changes apply to both Management API and Delivery API.

Structural Changes

Change Before After
OpenAPI Version 3.0.4 3.1.1
Nullable Representation "nullable": true "type": ["null", "string"] (OpenAPI 3.1 style)
oneOf Wrappers Present around single $ref Removed

Polymorphism Changes

Change Before After
anyOf usage Not used Used for polymorphic types
discriminator Varied Consolidated with propertyName: "$type"
Schema naming Concrete class names Interface-prefixed names

Delivery API Specific

Change Before After
Api-Key Authentication Header parameter Proper securitySchemes with security array
Response schema ApiContentResponseModel IApiContentResponseModel (matches declared interface)
uniqueItems: true Present on HashSet<Guid> params Removed (validation hint only)

Known Limitations

Polymorphic Type Schema Naming

Microsoft.AspNetCore.OpenApi prefixes derived type schema names with the base type name for polymorphic types.

Example:

  • Before: DocumentPropertyValuePermissionPresentationModel
  • After: IPermissionPresentationModelDocumentPropertyValuePermissionPresentationModel

This is a known limitation (dotnet/aspnetcore#58332). The discriminator values remain unchanged, so JSON serialization is unaffected. Client SDK type names will differ.

Test Plan

  • All existing unit tests pass
  • New unit tests added for transformers (69 tests)
  • OpenAPI document generates correctly for Management API
  • OpenAPI document generates correctly for Delivery API
  • Swagger UI loads and functions correctly
  • Client SDK regeneration produces compatible output
  • Authentication flows work in Swagger UI

Documentation

umbraco/UmbracoDocs#8021

…OpenApi`

Also installed `Swashbuckle.AspNetCore.SwaggerUI` for now to use as UI only.
Still missing polymorphism settings for both APIs
…ts project to avoid models mode exception being logged in tests
…tom transformers for handling enums and polymorphism
…ration

# Conflicts:
#	Directory.Packages.props
…ration

# Conflicts:
#	Directory.Packages.props
#	src/Umbraco.Cms.Api.Common/Configuration/ConfigureUmbracoSwaggerGenOptions.cs
#	src/Umbraco.Cms.Api.Common/OpenApi/EnumSchemaFilter.cs
#	src/Umbraco.Cms.Api.Common/OpenApi/MimeTypeDocumentFilter.cs
#	src/Umbraco.Cms.Api.Common/OpenApi/RemoveSecuritySchemesDocumentFilter.cs
#	src/Umbraco.Cms.Api.Common/OpenApi/SwaggerRouteTemplatePipelineFilter.cs
#	src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoDeliveryApiSwaggerGenOptions.cs
#	src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoMemberAuthenticationDeliveryApiSwaggerGenOptions.cs
#	src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs
#	src/Umbraco.Cms.Api.Delivery/Filters/SwaggerDocumentationFilterBase.cs
#	src/Umbraco.Cms.Api.Delivery/Filters/SwaggerMediaDocumentationFilter.cs
#	src/Umbraco.Cms.Api.Management/Configuration/ConfigureUmbracoManagementApiSwaggerGenOptions.cs
#	src/Umbraco.Cms.Api.Management/OpenApi.json
#	src/Umbraco.Cms.Api.Management/OpenApi/BackOfficeSecurityRequirementsOperationFilterBase.cs
#	src/Umbraco.Cms.Api.Management/OpenApi/NotificationHeaderFilter.cs
#	src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs
#	src/Umbraco.Cms.Api.Management/OpenApi/RequireNonNullablePropertiesSchemaFilter.cs
#	src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/backend-api/types.gen.ts
#	templates/UmbracoExtension/Composers/UmbracoExtensionApiComposer.cs
@lauraneto

Copy link
Copy Markdown
Contributor Author

@AndyButland I've made some changes since your last review and also created an issue in the ASP.NET Core repository, dotnet/aspnetcore#66340, so that we can eventually remove our workaround in https://github.com/umbraco/Umbraco-CMS/pull/21058/changes#diff-7416dbdc100a3dae0edff11951c554ab2954e4853fb404b86458c693ec395380.

@AndyButland AndyButland left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great @lauraneto, and in testing all seems to be working as expected. I've regenerated the typed client, and verified everything builds, the backoffice works as expected and the Swagger UI displays with the expected endpoint and model information.

The last few things I've found I think are non-controversial so I've committed them to save another round - but please have a look and if you have any concerns we can amend. Otherwise good to merge in I would say, please go ahead when you are happy to.

@lauraneto lauraneto enabled auto-merge (squash) April 29, 2026 13:26
@lauraneto lauraneto merged commit 5a545fa into v18/dev Apr 30, 2026
28 of 29 checks passed
@lauraneto lauraneto deleted the v18/feature/microsoft-open-api-document-generation branch April 30, 2026 19:12
lauraneto added a commit that referenced this pull request May 4, 2026
#22670)

* Update Umbraco extension template for OpenAPI route changes

Following the migration from Swashbuckle to Microsoft.AspNetCore.OpenApi
in #21058, the extension template still pointed at the old Swagger URL
pattern and used outdated terminology in code comments.

- generate-client npm script now points at /umbraco/openapi/{name}.json
  instead of /umbraco/swagger/{name}/swagger.json
- generate-openapi.js renames swaggerUrl to openApiUrl and updates the
  example URL in the missing-argument error message
- UmbracoExtensionApiComposer.cs comments updated from "Swagger" to
  "OpenAPI"

* Scope custom OpenAPI document to extension's own endpoints

Without an explicit ShouldInclude predicate, Microsoft.AspNetCore.OpenApi
only includes endpoints whose ApiExplorer GroupName equals the document
name. The template's controller declared a different group name, so the
custom document was created but stayed empty (paths: []), which in turn
made npm run generate-client produce an empty TypeScript SDK.

Filter by the [MapToApi] attribute already present on the extension's
controller base, mirroring the pattern used by the Management and
Delivery API options.

* Add Microsoft.AspNetCore.OpenApi reference to Central package management

The PerProject mode of the umbraco-extension template took a direct
dependency on Microsoft.AspNetCore.OpenApi (with a long comment
explaining why) but the Central mode did not, so default Central
scaffolds failed to build with the source-generator interceptors
error. Mirror the dependency in the Central csproj block and
Directory.Packages.props.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants