RicoSuter/NSwag

AspNetCoreOpenApiDocumentGenerator incorrectly generates query params with special path param names

Open

#2915 opened on Jun 19, 2020

View on GitHub
 (1 comment) (0 reactions) (0 assignees)C# (6,291 stars) (1,189 forks)batch import
help wantedproject: NSwag.CodeGeneration.CSharp (Controllers)

Description

Hi,

I am trying to generate a controller in my project from the swagger files in the Grafeas project. Specifically, I am experimenting with this file: https://github.com/grafeas/grafeas/blob/master/proto/v1beta1/swagger/project.swagger.json#L85

Note the highlighted line. The path parameter is {name=projects/*}. I am actually not sure what this template format means, as I wasn't able to find this format in the OpenAPI spec.

So I use this file to generate a controller, like so:

dotnet-nswag.exe openapi2cscontroller /input:project.swagger.json /classname:Test /output:TestController.cs /namespace:Test /UseActionResultType:true /ControllerStyle:Abstract /ControllerBaseClass:Microsoft.AspNetCore.Mvc.ControllerBase

This generates the following code (not the full class, just the relevant code snippet):

/// <summary>Gets the specified project.</summary>
/// <param name="name">The name of the project in the form of `projects/{PROJECT_ID}`.</param>
/// <returns>A successful response.</returns>
[Microsoft.AspNetCore.Mvc.HttpGet, Microsoft.AspNetCore.Mvc.Route("v1beta1/{name=projects/*}")]
public abstract System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.ActionResult<ProjectProject>> GetProject(string name);

And then I build an AspNetcore service that uses this controller. I also want NSwag to generate a Swagger, so I do (in ConfigureServices):

services.AddSwaggerDocument(x => { x.Title = Program.ApplicationName; });

And then in Configure:

app.UseOpenApi();
app.UseSwaggerUi3(x => x.DocumentTitle = $"{Program.ApplicationName} Swagger");

This will produce a Swagger page that marks the name parameter as a query param, even though it's defined in the source file that it should be a path param. The actual service works fine, so I can trigger the endpoint via v1beta1\<name>, so the problem seems to be with only the Swagger generation.

If I manually change the path parameter in the generated controller route from "v1beta1/{name=projects/*}" to "v1beta1/{name}", then the Swagger page is correctly generated. I suspect NSwag somewhere picks up the equals sign and assumes that it's a query param.

Unfortunately, I am consuming the original swagger definitions from a 3rd party project (Grafeas), so changing them is not an option.

I can work around this by applying the [Route("v1beta1/{name")] attribute on my derived class from the abstract controller, but I would prefer not to duplicate these routes on every method I am implementing.

There is another file in the API spec, which has a lot more methods and Swagger generation actually breaks with that file, because there are multiple endpoints with the same route (since they are generated with a query param).

I have tested this on https://generator.swagger.io/, and by putting in the raw file there, it generates the correct Swagger page, so I would assume that the original json file is correct.

Thanks for looking into this, Balazs

Contributor guide