RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.78k stars 1.29k forks source link

C# templated path parameter being set as FromHeader #2046

Open jimcullenaus opened 5 years ago

jimcullenaus commented 5 years ago

Observed problem

I have a parameter in OpenAPI that has in: path on it.

It is being generated in to .netcore C# code as [Microsoft.AspNetCore.Mvc.FromHeader].

I can not find any way to detect in the controller liquid template to differentiate between header and path parameters.

Sample code

I have the following OpenAPI specification:

...
  /v1/users/{userId}/session:
    parameters:
      - $ref: '#/components/parameters/UserId'
    put:
      parameters:
        - $ref: '#/components/parameters/ApiKey'
      operationId: InitiateLoginAttempt
...
components:
  parameters:
    ApiKey:
      in: header
      name: ApiKey
      description: A key used to identify that the device making the call is one with the correct credentials.
      schema:
        type: string
        format: uuid
      required: true
    UserId:
      name: userId
      in: path
      required: true
      description: A user's user id.
      schema:
        type: string

And am generating C# .netcore code using the following template:

[{{ AspNetNamespace }}.Http{{ operation.HttpMethodUpper }}, {{ AspNetNamespace }}.Route("{{ operation.Path }}"{% if operation.HasRouteName %}, Name = "{{ operation.RouteName }}"{% endif %})]
    public {% if operation.WrapResponse %}async System.Threading.Tasks.Task<HttpResponseMessage>{% else %}{{ operation.ResultType }}{% endif %} {{ operation.ActualOperationName }}(
        {% for parameter in operation.Parameters %}
            {% if parameter.IsBody %}
                [{{ AspNetNamespace }}.FromBody] {{ parameter.Type }} {{ parameter.VariableName }}
            {% else %}
                [{{ AspNetNamespace }}.FromHeader] {{ parameter.Type }} {{ parameter.VariableName }}
            {% endif %}
        {% endfor %}

The output result is (with manual formatting changes for ease of reading):

[Microsoft.AspNetCore.Mvc.HttpPut, Microsoft.AspNetCore.Mvc.Route("v1/users/{userId}/session")]
        public System.Threading.Tasks.Task<LoginSessionCreatedResponse> InitiateLoginAttempt(
                    [Microsoft.AspNetCore.Mvc.FromHeader] System.Guid apiKey,
                    [Microsoft.AspNetCore.Mvc.FromBody] SessionInitiationRequest body,
                    [Microsoft.AspNetCore.Mvc.FromHeader] string userId
            )

As a result, when the code is called, userId is always null, because it is from the route, not the header. If I manually change FromHeader to FromRoute, it works fine. Unfortunately, I can find no way in the liquid template to detect that a parameter has the OpenApi in: path option set. parameter.IsBody works as expected, but none of .IsPath, .IsRoute, .IsHeader, or .IsHead ever evaluate to anything.

Expected behaviour

operation.Parameters should contain items that have a IsBody, IsPath and IsHeader property on them, and this should match the in value for the parameter from the OpenAPI specification.

drewfreyling commented 5 years ago

Is there anything holding this up PR?

RicoSuter commented 5 years ago

The PR is not against this repo!?

jimcullenaus commented 5 years ago

@drewfreyling the intent was to get it tested and approved in our own repo first before pushing to this one. I didn't even realise that linking off Issue for reference would notify this thread about it. Unfortunately I didn't know how to test and nobody else considered it priority.