Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Error: "Not supported by Swagger 2.0: Multiple operations with path 'api/Products' and method 'GET'" #142
Hm... I see in the README that Swagger 2.0 does not include the query string component when mapping a URL to an action.
Phew. Is there any generic solution for that? We (and others, I figure) do have a lot of APIs with query strings and a standard route like
Unfortunately this is a constraint imposed by the Swagger specification https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md.
I had some late involvement with the Swagger 2.0 working group and pushed hard to have this constraint removed but to no avail. As you pointed out, this does cause an issue for certain WebApi implementations. I'll describe the workaround below but first I want to play devil's advocate and look at it from an API perspective, agnostic of implementation frameworks or even specific language constructs.
In it's essence, the constraint really just says the following paths have to be described as one operation.
Behind the scenes these may be implemented as separate C# or separate Java methods, but in the context of describing a REST API, would you describe them separately? Swagger 2.0 says "No ... it's one operation with an optional productType parameter".
Technically, I believe they are two different resources (hence why I opposed the constraint) but I do see some sense in the Swagger 2.0 approach. For example, I don't think I've ever seen any API docs broken down this way - it's invariably just by path with additional information about query parameters included.
Anyway, philosophy aside - breaking the Swagger 2.0 spec is not an option and so I can only provide some workarounds.
The most straight forward would be to consolidate your multiple, "overloaded", actions with a single action with optional parameters. You could even delegate internally to the private overloaded versions.
If a change to the implementation isn't an option - Swashbuckle 5.0 provides a config setting ResolveConflictingActions. This takes a function of the form - Func<<IEnumerable<ApiDescription>, ApiDescription> which you can provide to consolidate the actions into one ApiDescription, and therefore one Operation, at the documentation level only.
This "merge" process will get trickier if the response type and errors codes also differ but at that point you'd have to ask questions about the API design.
Hope this helps - let me know if it makes sense?
and one method for getting product details like this:
is a very common scenario.
So yes: changing the implementation is not an option.
True, it's extremely common to have a "collection" resource and corresponding "item" resource. However, the standard approach here would be to use a "path" parameter for the id:
If you're early in your API design, I would strongly advice this approach. It's a widely accepted standard in REST design. In fact it's reflected by the default route template when you create a new WebApi project:
Swagger will have no problem with this because the two different operations can be distinguished by path alone. If you want to go against the grain and represent the two different operations as follows:
Then you will find it very difficult to describe your API with Swagger. Although it does represent best practice, I do think Swagger 2.0 is a little too opinionated in this regard. Swashbuckle provides good workarounds and frankly, can't do much more. If you feel very strongly about this, I would recommend posting an issue here - https://github.com/swagger-api/swagger-spec
This was referenced
Feb 18, 2015
True, it's not ideal! However, I still maintain that it's due to an overly opinionated constraint in the Swagger specification and with that being the root cause, maybe worth posting an issue there.
The bottom line is this ... because of this constraint, you CANNOT describe the actions as separate Swagger Operations and so, the corresponding ApiDescriptions have to be merged into one for the Swagger document to be generated. This is what the ResolveConflictingActions option is for.
It's also worth noting that you're not limited to just taking the first description, you're free to implement any merge strategy you like. For example, if the actions share the same response type and only differ in parameters, you could return a completely new ApiDescription that includes a union of parameters, marking the non-common ones as optional.
Finally, if they don't share the same response type ... then, at an API level (independent of SB, C# or any server-side frameworks) you simply won't be able to describe your API with Swagger.
The workaround specified in the documentation won't work.
cuz apiDescription is of type IEnumerable and not an ICollection or IList
My workaround has been to use hashes to show the same endpoint multiple times. Does the job even though swaggerui may look a little untidy. So my json output ends up being something like:
Obviously the hashes don't get POSTed and the APIs work as expected.
@philals I didn't do this in C# but going by your above example, maybe something like this:
There is one more solution to this, but it's a deviation from Swagger 2.0 spec.
You can implement ISwaggerProvider using the current class SwaggerGenerator. To cut long story short, just copy-paste the class from the original source to ISwaggerProvider implementation and initialize private fields using reflection. The provider can be added by means of the standard way through the configuration. In your implementation you should change only one line of code to allow multiple operations (example):
That will solve the problem w/o necessity to merge actions.
referenced this issue
Oct 17, 2016
The first part of this article solved this issue for me: https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-dotnet-swashbuckle-customize. No need to change my API, just add a custom operation filter that generates unique ids for each operation for swagger. API remains unchanged otherwise.