question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Issues with auto-generated operationId

See original GitHub issue

Currently, the operationId is generated as a combination of controller name and action:

public static string FriendlyId(this ApiDescription apiDescription)
{
    return String.Format("{0}_{1}",
        apiDescription.ActionDescriptor.ControllerDescriptor.ControllerName,
        apiDescription.ActionDescriptor.ActionName);
}

In certain scenarios (e.g. overloading the action name for different routes) this can result in the same operationId for multiple operations, thus breaking the Swagger 2.0 constraint that operation Id’s must be unique within a Swagger document.

The obvious solution would be to instead use a combination of HTTP method and route template. However, this presents a challenge related to the second Swagger 2.0 constraint - namely that operationId should be “friendly” as it MAY be used as a method name in auto-generated clients. For example, the following would not be possible in a JavaScript client:

swaggeClient.pets.GET_pets/{id}

The following would be preferable:

swaggerClient.pets.GetPetById

So, we need to come up with a deterministic (consider complex, nested routes) approach for generating an operationId that is both “unique” and “friendly”.

Suggestions welcome?

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:4
  • Comments:11 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
dariusdamalakascommented, Apr 16, 2016

@domaindrivendev , we faced similar issue, so what we’ve come up was to generate as friendly operation IDs as we can by following a pattern: <verb><context><resource><action> :

  1. <resource> is the resource name for which the operation is applied, e.g. document, client, company, etc
  2. <action> is any action that is applied on the resource, such as share, upload, etc
  3. <verb> is http action verb:
    • GET (single)-> Get
    • GET (colleciton) -> List
    • POST -> Create,
    • Delete -> Delete
    • Put -> Update
    • Head -> Exists
  4. <context> is usually any parent resources under which resource is nested.

This ends up nicely in the following auto-generated operation IDs. See below table for an example. We have this implemented and working, all covered 100% with unit tests. Obviously, there is an attribute that can be applied to override this auto-generated ID.

Url Verb Operation ID
/v1/documents/{documentId}/share post ShareDocument
/v1/documents/{documentId}/content get GetDocumentContent
/v1/documents/{documentId}/content put UpdateDocumentContent
/v1/documents/{documentId} get GetDocument
/v1/documents/{documentId} post CreateDocument
/v1/documents/{documentId} delete DeleteDocument
/v1/documents/{documentId} put UpdateDocument
/v1/documents/statistics get GetDocumentStatistics
/v1/documents get ListDocuments
/v1/documents post CreateDocuments
/v1/clients/{clientId}/documents/{documentId}/content get GetClientDocumentContent
/v1/clients/{clientId}/documents/{documentId} get GetClientDocument
/v1/clients/{clientId}/documents get ListClientDocuments
0reactions
gmarianocommented, May 3, 2021

I recently ran into the same problem and I solved it using Swashbuckle Operation Filter. The following code generates operation ids based on controller and action names, adding a numeric suffix to the operationId if one with the same id already exists:

using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace Api.Swagger
{
    [UsedImplicitly]
    public class SwaggerOperationIdFilter : IOperationFilter
    {
        private readonly Dictionary<string, string> _swaggerOperationIds = new Dictionary<string, string>();

        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            if (!(context.ApiDescription.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor))
            {
                return;
            }

            if (_swaggerOperationIds.ContainsKey(controllerActionDescriptor.Id))
            {
                operation.OperationId = _swaggerOperationIds[controllerActionDescriptor.Id];
            }
            else
            {
                var operationIdBaseName = $"{controllerActionDescriptor.ControllerName}_{controllerActionDescriptor.ActionName}";
                var operationId = operationIdBaseName;
                var suffix = 2;
                while (_swaggerOperationIds.Values.Contains(operationId))
                {
                    operationId = $"{operationIdBaseName}{suffix++}";
                }

                _swaggerOperationIds[controllerActionDescriptor.Id] = operationId;
                operation.OperationId = operationId;
            }
        }
    }
}
services.AddSwaggerGen(options =>
            {
                options.OperationFilter<SwaggerOperationIdFilter>();
            ...

https://g-mariano.medium.com/generate-readable-apis-clients-by-setting-unique-and-meaningful-operationid-in-swagger-63d404f32ff8

Read more comments on GitHub >

github_iconTop Results From Across the Web

Issues with auto-generated operationId #300
Currently, the operationId is generated as a combination of controller name and action: public static string FriendlyId(this ApiDescription ...
Read more >
FATAL: OperationId is required for all operations. Please ...
I found a Github question / issue where people addressed this by configuring AutoRest to use tags instead of operation ID to identify...
Read more >
OpenAPI Code Generator - Tulip Community
The OpenAPI code generator makes client libraries from a swagger API.
Read more >
Using OpenAPI Auto-Generated Clients in ASP.NET Core
So let's see a few ways to improve the generated code. My first tip, is that your Swagger file should include an operationId...
Read more >
API import restrictions and known issues - Azure
Details of known issues and restrictions on OpenAPI, WSDL, and WADL formats support in Azure API Management.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found