22

How can I set swagger operationId attribute in Asp.Net Core 2.1 project? According to this post I should use SwaggerOperationAttribute but I cannot find it in Swashbuckle.AspNetCore library. Also there is an IOperationFilter

public interface IOperationFilter
{
    void Apply(Operation operation, OperationFilterContext context);
}

and I can't find any implementations for swagger generation purposes.

phoenix
  • 7,988
  • 6
  • 39
  • 45
  • 2
    Go directly to the source: https://github.com/domaindrivendev/Swashbuckle.AspNetCore#extend-generator-with-operation-schema--document-filters – Helder Sepulveda Sep 11 '18 at 01:13
  • @HelderSepu according to [documentation](https://github.com/domaindrivendev/Swashbuckle.AspNetCore#assign-explicit-operationids) I should specify Name parameter in HttpGet attribute: `[HttpGet("{id:int}", Name = "GetById")]`, but it still generates this json: `"operationId": "ApiV1ApplicationsByIdGet"` – Александр Сысоев Sep 11 '18 at 09:07
  • If the documentation says something that is not doing that is potentially a bug, you should report it in the project. – Helder Sepulveda Sep 11 '18 at 12:34
  • I think this is a bug, I'm experiencing the same issues after updating to Swashbuckle.AspNetCore 3.0.0. – garie Oct 24 '18 at 20:39
  • Filed: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/921 – garie Oct 24 '18 at 20:54
  • Not a bug. I commented on the Github issue: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/921#issuecomment-433293323 – jro Oct 26 '18 at 05:46

7 Answers7

52

There are 2 other options without having to write any extra code or add extra dependency like Swashbuckle.AspNetCore.Annotations

Option 1: Convention based - SwaggerGen has an option to set CustomOperationIds. So you can simply set it to use ControllerName_HttpMethod like this:

services.AddSwaggerGen(c =>
{
    c.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["controller"]}_{e.HttpMethod}");
    c.SwaggerDoc("v1", new Info { Title = "Test API", Version = "v1" });
});

This will add operationIds to all your methods, following ControllerName_HttpMethod convention.

Option 2: ActionFilter/Attribute based - you can configure each Action method (as you'd do with SwaggerOperation action filter by simple adding a Name property to your HTTP verb action filter like this:

[HttpPost(Name="Post_Person")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<ActionResult<Response>> PostAsync([FromBody]Request request)
{
    Response result = await _context.PostAsync(request);
    return Ok(result);
}

This works exactly like [SwaggerOperation(OperationId = "Post_Person")] but without the need of EnableAnnotations

phoenix
  • 7,988
  • 6
  • 39
  • 45
CoOl
  • 2,637
  • 21
  • 24
  • Is there a way to have `Swashbuckle` infer the `Name` based on the method name? In the example above, have it infer the name `PostAsync`? – phoenix May 21 '21 at 17:20
  • 2
    @phoenix A late answer. Simply change to `ActionDescriptor.RouteValues["action"]` would work. I've added another answer below too. – Bowen May 17 '22 at 02:41
9

Adding a Name parameter to [HttpGet]/[HttpPost] fails with an exception in the most recent version, but putting a Name parameter on the Route attribute seems to work:

/// <summary>
/// Get all devices
/// </summary>
[Route("devices", Name = "GetAllDevices")]
[Authorize]
[HttpGet]
[Produces(typeof(Device[]))]
public async Task<IActionResult> GetAllDevices() { ...}
Pang
  • 9,564
  • 146
  • 81
  • 122
Ian Mercer
  • 38,490
  • 8
  • 97
  • 133
  • 1
    I concur! Many thanks. The exception I get is that standard routing is not allowed with ApiExplorer or something like that. I think this is the 'correct', currently. – Frank Jan 06 '21 at 09:50
5

You can also generate the operation id based on the action name which is the method name, I found this handy when generating the API client.

services.AddSwaggerGen(c =>
{
    c.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["action"]}");
    c.SwaggerDoc("v1", new Info { Title = "Test API", Version = "v1" });
});
Bowen
  • 381
  • 6
  • 11
3

Finally, I came to this solution:

public class SwaggerOperationNameFilter : IOperationFilter
{
    public void Apply(Operation operation, OperationFilterContext context)
    {
        operation.OperationId = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
            .Union(context.MethodInfo.GetCustomAttributes(true))
            .OfType<SwaggerOperationAttribute>()
            .Select(a => a.OperationId)
            .FirstOrDefault();
    }
}

[AttributeUsage(AttributeTargets.Method)]
public sealed class SwaggerOperationAttribute : Attribute
{
    public SwaggerOperationAttribute(string operationId)
    {
        OperationId = operationId;
    }

    public string OperationId { get; }
}

// Startup.cs
services.AddSwaggerGen(c =>
{
    ...
    c.OperationFilter<SwaggerOperationNameFilter>();
};

[HttpGet("{id:int}")]
[SwaggerOperation("GetById")]
public async Task<IActionResult> Get(int id)
{
    ...
}

But it still seems to me that I've reinvented the wheel.

Pang
  • 9,564
  • 146
  • 81
  • 122
3

You can enable annotation on swagger with the Swashbuckle.AspNetCore.Annotations NuGet package. (https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md#swashbuckleaspnetcoreannotations)

Once annotations have been enabled, you can enrich the generated Operation metadata by decorating actions with a SwaggerOperationAttribute.

[HttpPost]

[SwaggerOperation(
    Summary = "Creates a new product",
    Description = "Requires admin privileges",
    OperationId = "CreateProduct",
    Tags = new[] { "Purchase", "Products" }
)]
public IActionResult Create([FromBody]Product product)
Pang
  • 9,564
  • 146
  • 81
  • 122
Grig M
  • 31
  • 4
3

Its pretty simple

Add EnableAnnotations in ConfigureService Method

            {
                options.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title = "Project HTTP API",
                    Version = "v1",
                    Description = "...."
                });
                options.EnableAnnotations();
            });

And use in controllers

[SwaggerOperation(OperationId = "GET_API")]

You can see in this in Swagger Json as

get": {
        "tags": [
          "API"
        ],
        "summary": "....",
        "operationId": "GET_API"
}
Akshay H
  • 216
  • 2
  • 8
1

add this line - swagger.CustomOperationIds(e => $"{e.RelativePath}"); in services.AddSwaggerGen function call

Yogesh Patil
  • 151
  • 1
  • 6