Skip to content

feat: adds support for initializing the OpenAPI document for tag metadata in 3.2.0#67457

Open
baywet wants to merge 5 commits into
dotnet:mainfrom
baywet:feat/pre-generation-openapi-hook
Open

feat: adds support for initializing the OpenAPI document for tag metadata in 3.2.0#67457
baywet wants to merge 5 commits into
dotnet:mainfrom
baywet:feat/pre-generation-openapi-hook

Conversation

@baywet

@baywet baywet commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

fixes #65723

Example use

using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
using System.Text.Json.Nodes;

builder.Services.AddOpenApi(options =>
{
    options.AddDocumentInitializer((document, context, cancellationToken) =>
    {
        document.Tags ??= [];

        document.Tags.Add(new OpenApiTag
        {
            Name = "commerce",
            Summary = "Commerce",
            Description = "Top-level APIs for commerce workflows.",
            Kind = "nav",
            ExternalDocs = new OpenApiExternalDocs
            {
                Description = "Commerce API guide",
                Url = new Uri("https://docs.example.com/apis/commerce")
            }
        });

        document.Tags.Add(new OpenApiTag
        {
            Name = "orders",
            Summary = "Orders",
            Description = "Create, update, and track customer orders.",
            Parent = new OpenApiTagReference("commerce", document),
            Kind = "section",
            ExternalDocs = new OpenApiExternalDocs
            {
                Description = "Orders guide",
                Url = new Uri("https://docs.example.com/apis/commerce/orders")
            }
        });

        document.Tags.Add(new OpenApiTag
        {
            Name = "payments",
            Summary = "Payments",
            Description = "Authorize, capture, refund, and reconcile payments.",
            Parent = new OpenApiTagReference("commerce", document),
            Kind = "section",
            ExternalDocs = new OpenApiExternalDocs
            {
                Description = "Payments guide",
                Url = new Uri("https://docs.example.com/apis/commerce/payments")
            }
        });

        return Task.CompletedTask;
    });
});

Equivalent using a document transformer has to wait until operation generation has already populated document.Tags , then find each tag and mutate it:

using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
using System.Text.Json.Nodes;

builder.Services.AddOpenApi(options =>
{
    options.AddDocumentTransformer((document, context, cancellationToken) =>
    {
        var commerce = GetRequiredTag(document, "commerce");
        commerce.Summary = "Commerce";
        commerce.Description = "Top-level APIs for commerce workflows.";
        commerce.Kind = "nav";
        commerce.ExternalDocs = new OpenApiExternalDocs
        {
            Description = "Commerce API guide",
            Url = new Uri("https://docs.example.com/apis/commerce")
        };

        var orders = GetRequiredTag(document, "orders");
        orders.Summary = "Orders";
        orders.Description = "Create, update, and track customer orders.";
        orders.Parent = new OpenApiTagReference("commerce", document);
        orders.Kind = "section";
        orders.ExternalDocs = new OpenApiExternalDocs
        {
            Description = "Orders guide",
            Url = new Uri("https://docs.example.com/apis/commerce/orders")
        };

        var payments = GetRequiredTag(document, "payments");
        payments.Summary = "Payments";
        payments.Description = "Authorize, capture, refund, and reconcile payments.";
        payments.Parent = new OpenApiTagReference("commerce", document);
        payments.Kind = "section";
        payments.ExternalDocs = new OpenApiExternalDocs
        {
            Description = "Payments guide",
            Url = new Uri("https://docs.example.com/apis/commerce/payments")
        };

        return Task.CompletedTask;
    });
});

static OpenApiTag GetRequiredTag(OpenApiDocument document, string name)
{
    var tag = document.Tags?.SingleOrDefault(tag => tag.Name == name);

    if (tag is null)
    {
        throw new InvalidOperationException($"The OpenAPI document does not contain a '{name}' tag.");
    }

    return tag;
}

Another important aspect to the initializer is that it guarantees the order of the tags is matching their insertion order, not whatever random order the operations are declared in/we're processing them. And it doesn't require further mutations of the collection (not demonstrated in the examples). This is especially important when driving documentation experiences where table of contents might depend on the order of tags.

CC @martincostello

Copilot AI review requested due to automatic review settings June 29, 2026 12:19
@baywet baywet requested a review from a team as a code owner June 29, 2026 12:19
…data in 3.2.0

Signed-off-by: Vincent Biret <vincentbiret@hotmail.com>
@baywet baywet force-pushed the feat/pre-generation-openapi-hook branch from 6082e25 to 29bf81e Compare June 29, 2026 12:19

Copilot AI 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.

Pull request overview

Adds a new pre-generation customization hook for ASP.NET Core’s OpenAPI document generation so callers can initialize document-level metadata (e.g., global tag metadata for OpenAPI 3.2) before paths/operations/components are produced.

Changes:

  • Introduces IDocumentInitializer plus delegate/type-based implementations and OpenApiOptions.AddDocumentInitializer(...) registration APIs.
  • Updates OpenApiDocumentService to run registered document initializers after base document creation and before path/operation generation.
  • Adds test coverage validating initializer registration and that initializers run before operations are generated.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Transformers/OpenApiOptionsTests.cs Adds tests for registering document initializers via delegate/instance/type.
src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Transformers/DocumentTransformerTests.cs Adds an integration-style test verifying initializer execution order relative to operation generation.
src/OpenApi/src/Transformers/TypeBasedDocumentInitializer.cs Adds DI-activated initializer wrapper with proper disposal semantics.
src/OpenApi/src/Transformers/IDocumentInitializer.cs Introduces the new public initializer interface.
src/OpenApi/src/Transformers/DelegateDocumentInitializer.cs Adds delegate-backed initializer wrapper.
src/OpenApi/src/Services/OpenApiOptions.cs Adds DocumentInitializers storage and AddDocumentInitializer overloads.
src/OpenApi/src/Services/OpenApiDocumentService.cs Executes document initializers before generating document paths/operations.
src/OpenApi/src/PublicAPI.Unshipped.txt Declares new public API surface for the initializer feature.
Comment thread src/OpenApi/src/Transformers/IOpenApiDocumentInitializer.cs

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread src/OpenApi/src/Services/OpenApiDocumentService.cs

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread src/OpenApi/src/Transformers/IOpenApiDocumentInitializer.cs Outdated

Copilot AI 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.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jun 29, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Thanks for your PR, @baywet. Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

baywet and others added 4 commits June 29, 2026 12:02
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@baywet baywet force-pushed the feat/pre-generation-openapi-hook branch from 2149d28 to f0aaf40 Compare June 29, 2026 16:02
@baywet baywet requested a review from Copilot June 29, 2026 16:03

Copilot AI 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.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-contribution Indicates that the PR has been added by a community member

2 participants