Nswag: [NSwagStudio] Nullable Timespan in ASP web api 2 generates different C# method signature when using Output type of "OpenApi3" vs "Swagger2"

Created on 27 Sep 2018  ·  16Comments  ·  Source: RicoSuter/NSwag

Hey,
I'm using NSwagStudio x64 v11.19.2.0
With below ASP web api 2 controller:

    [RoutePrefix("api/values")]
    public class ValuesController : ApiController
    {
        [HttpPut, Route("{id}/expiry")]
        [SwaggerResponse(200, typeof(bool))]
        public async Task<IHttpActionResult> PutExpiry([FromUri] string id, [FromBody] TimeSpan? expiry)
        {
            await Task.Yield();

            var success = true;
            return Ok(success);
        }
    }

    public class ValueDto
    {
        [Required]
        public string Id { get; set; }
    }

In NSwag Studio I get different C# client when selecting Swagger2 vs OpenApi3.

Swagger2:

public System.Threading.Tasks.Task<bool> PutExpiryAsync(string id, System.TimeSpan? expiry)

OpenApi3:

public System.Threading.Tasks.Task<bool> PutExpiryAsync(string id, System.TimeSpan expiry)

Notice in OpenApi3 the System.TimeSpan is not nullable.
For now I manually change the generated code to 'TimeSpan?', but fear another dev might overwrite it in future when they re-generate client.

Most helpful comment

I've added AllowNullableBodyParameters setting (default: true) - now nullable should be correctly handled in OpenAPI 3 (without changing anything). In the next major release (v12) the default will be set to false to reflect the current implementation of ASP.NET Core 2+... Keeping default true to not break anyone now.

All 16 comments

The next version (on master) should improve Open API 3 a lot and fix that... will check that with the latest version.

The spec is generated with NSwag?

The spec was generated with NSwagStudio in the outputs pane (so i think so).
I specified the path to the ASP Web api 2 assembly file in input pane, then click generate outputs: which generates the Specification and C# client.

When is the next release (from master) for NSwagStudio expected, and will i be able to download it from http://rsuter.com/Projects/NSwagStudio/installer.php ?

You can download it here: https://ci.appveyor.com/project/rsuter/nswag-25x6o/build/artifacts

But you have to first uninstall the current version (because the latest version has the same version as the released one which might lead to problems). Just check that the used NJsonSchema version is v9.11.0 (can be found on top of the spec/clients).

Unfortunately the issue still persists in https://ci.appveyor.com/api/buildjobs/v9mlpx87hjtsb1ah/artifacts/src%2FNSwagStudio.Installer%2Fbin%2FRelease%2FNSwagStudio.msi

I still see the TimeSpan parameter generated for OpenApi3 in the above msi.
openapi3_timespan
swagger2_timespan

Looks good to me:

image

(but with the api explorer version)

Can you post the generated spec?

Below is the OpenApi3 json spec by NswagStudio:

{
  "x-generator": "NSwag v11.19.2.0 (NJsonSchema v9.11.0.0 (Newtonsoft.Json v9.0.0.0))",
  "openapi": "3.0.0",
  "info": {
    "title": "My Title",
    "version": "1.0.0"
  },
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/api/values/{id}/expiry": {
      "put": {
        "tags": [
          "Values"
        ],
        "operationId": "Values_PutExpiry",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "nullable": true
            },
            "x-position": 1
          }
        ],
        "requestBody": {
          "x-name": "expiry",
          "content": {
            "application/json": {
              "schema": {
                "type": "string",
                "format": "time-span"
              }
            }
          },
          "required": true,
          "x-position": 2
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "boolean"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {}
}

Ah, it's a body parameter, this is the problem:

image

After some research I got to this conclusion:

Important for client generators:

  • Swagger 2.0 makes a parameter nullable if it is not required
  • OpenAPI 3 makes a parameter nullable if it is marked with nullable = true OR if it is not required

ASP.NET Core

  • By default does not support nullable body parameters, but this can be enabled with the AllowEmptyInputInBodyModelBinding setting, @pranavkm is this nullability info somehow exposed by apiParameter (couldnt find a property which worked)?
  • In ASP.NET Core body parameters are always required and not nullable ATM, so in the client they are always not nullable

Web API

  • I think in web api 2, null as body parameter is allowed
  • Swagger 2 uses x-nullable which is correctly set, but openapi3 uses the nullable property on the schema which is not correctly set ATM

I've added AllowNullableBodyParameters setting (default: true) - now nullable should be correctly handled in OpenAPI 3 (without changing anything). In the next major release (v12) the default will be set to false to reflect the current implementation of ASP.NET Core 2+... Keeping default true to not break anyone now.

… but eventually, we should load the nullable information from API Explorer.

Thanks I appreciate the swift fix.
Is there a NSwagStudio msi I should try to verify this fix ?

I think same link theres a new option in the ui

v11.20.0 is released, please retest - hope my last commit didnt break it - but it's asp.net core 2+ only...

Just verified :-) works on x64 11.20.0.0.

Was this page helpful?
0 / 5 - 0 ratings