Skip to content

Allow setting a group name for endpoints and have it be used to populate ApiDescription.GroupName in ApiExplorer for minimal APIs #34541

Closed
@DamianEdwards

Description

@DamianEdwards

APIs described by Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription can optionally have a group name defined by the GroupName property. Today in the framework there isn't a way provided to set the group name for an endpoint via its metadata and the EndpointMetadataApiDescriptionProvider does not set ApiDescription.GroupName when it populates ApiExplorer with details of the registered endpoints.

ApiDescription.GroupName is used by frameworks like Swashbuckle to associate APIs with different OpenAPI documents, i.e. if the document name and API group name match the API is included in the document (see default logic here).

We should allow for setting the group name for endpoints via their metadata and have that used to populate the ApiDescription.GroupName property when the endpoints are added to ApiExplorer.

Proposed types for addition:

namespace Microsoft.AspNetCore.Routing;

/// <summary>
/// Declares the group name for this endpoint method or delegate.<br />
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate, Inherited = false, AllowMultiple = false)]
public sealed class EndpointGroupNameAttribute: Attribute, IEndpointGroupNameMetadata
{
    public EndpointGroupNameAttribute(string endpointGroupName)
    {
        if (endpointGroupName == null)
        {
            throw new ArgumentNullException(nameof(endpointGroupName));
        }

        EndpointGroupName = endpointGroupName;
    }

    /// <summary>
    /// The endpoint group name.
    /// </summary>
    public string EndpointGroupName { get; }
}

/// <summary>
/// Specifies an endpoint group name in Microsoft.AspNetCore.Http.Endpoint.Metadata.
/// </summary>
public class EndpointGroupNameMetadata : IEndpointGroupNameMetadata
{
    public EndpointGroupNameMetadata(string endpointGroupName)
    {
        if (endpointGroupName == null)
        {
            throw new ArgumentNullException(nameof(endpointGroupName));
        }

        EndpointGroupName = endpointGroupName;
    }

    /// <summary>
    /// The endpoint group name.
    /// </summary>
    public string EndpointGroupName { get; }
}

/// <summary>
/// Defines a contract use to specify an endpoint group name in Microsoft.AspNetCore.Http.Endpoint.Metadata.
/// </summary>
public interface IEndpointGroupNameMetadata
{
    /// <summary>
    /// The endpoint group name.
    /// </summary>
    string EndpointGroupName { get; }
}

Proposed extension methods for addition:

namespace Microsoft.AspNetCore.Builder;

public static class RoutingEndpointConventionBuilderExtensions
{
+    /// <summary>
+    /// Adds an EndpointGroupNameMetadata item to the Metadata for all endpoints produced by the builder.
+    /// </summary>
+    /// <param name="builder"></param>
+    /// <param name="groupName"></param>
+    /// <returns>The Microsoft.AspNetCore.Builder.IEndpointConventionBuilder.</returns>
+    public static TBuilder WithGroupName<TBuilder>(this TBuilder builder, string groupName) where TBuilder : IEndpointConventionBuilder
+    {
+        builder.WithMetadata(new EndpointGroupNameMetadata(groupName));
+
+        return builder;
+    }
}

Example of these new types and methods being used with minimal APIs:

app.MapGet("/hello/{name}", (string name) => $"Hello {name}")
   .WithName("SayHelloToName")
   .WithGroupName("NameApi")

app.MapGet("/todos/get-all", async (TodoDb db) => await db.Todos.ToListAsync())
   .WithName("GetAllTodos")
   .WithGroupName("TodoApi");

Metadata

Metadata

Assignees

Labels

Priority:1Work that is critical for the release, but we could probably ship withoutarea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcenhancementThis issue represents an ask for new feature or an enhancement to an existing onefeature-minimal-actionsController-like actions for endpoint routingold-area-web-frameworks-do-not-use*DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions