Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mark strings as non-nullable in ASP.NET Core 3.0 Swagger

I'm using ASP.NET Core 3 and Swashbuckle with mostly default configuration and I have a DTO parameter with a string on it that I want to be non-nullable. How can I achieve this? Note, Required and nullability are separate concerns in Swagger.

It's also using C#8 and the non-nullable stuff, so the compiler should be annotating the property as non-nullable already. It's understandable that Swashbuckle hasn't been updated to take that into account (and maybe can't) but I would like to be able to override the generated metadata somehow.

class MyDto {
    [Required]
    // I want this to show as non-nullable in the swagger documentation (and ideally also be non-nullable in the binding)
    public string TestProp { get; set; }
}

[HttpPost]
public void Post([FromBody] MyDto requestModel) {
}

I have tried making it Required. I also tried adding the Newtonsoft annotations, but none of these seemed to do it.

Relevant bit of Swagger doc that is generated:

    "MyDto": {
      "required": [
        "testProp"
      ],
      "type": "object",
      "properties": {
        "testProp": {
          "type": "string",
          "nullable": true
        }
      },
      "additionalProperties": false
     }

Note that having a string parameter directly as a parameter doesn't generate the nullable attribute. E.g.

[HttpPost("testPost")]
public void Post([FromBody] [Required] string testProp) {
}

will generate

"/api/test/testPost": {
  "post": {
    "tags": [
      "Test"
    ],
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "type": "string"
          }
        },
        "text/json": {
          "schema": {
            "type": "string"
          }
        },
        "application/*+json": {
          "schema": {
            "type": "string"
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "Success"
      }
    }
  }
},
like image 230
Quails4Eva Avatar asked Oct 09 '19 08:10

Quails4Eva


2 Answers

You can now use nullable reference types to mark strings as optional or required:

  • Enable nullable reference types for your project/solution

  • Mark strings in Dtos as nullable:

    public class ExampleDto
    {
       [StringLength(64, MinimumLength = 4)]
       public string RequiredString { get; set; }
    
       [StringLength(200)]
       public string? OptionalString { get; set; }
    }
    
  • Enable Swagger support in your Startup.cs

    services.AddSwaggerGen(options =>
    {
        options.SupportNonNullableReferenceTypes();
    });
    

This leads to:

{
  "Example": {
    "type": "object",
    "properties": {
      "requiredString": {
        "maxLength": 64,
        "minLength": 4,
        "type": "string"
      },
      "optionalString": {
        "maxLength": 200,
        "minLength": 0,
        "type": "string",
        "nullable": true
      }
    },
    "additionalProperties": false
  }
}
like image 158
PeterB Avatar answered Nov 09 '22 20:11

PeterB


Until v4.01 nullable:true was emitted for optional strings. This broke in the first 5.0 RC versions and nullable:true wasn't emitted at all for optional strings. That, obviously, is wrong.

Starting with 5.0 RC3 optional strings are nullable once again.

To specify that an optional string is not nullable, you need to add [JsonProperty(Required = Required.DisallowNull)] to the property. Copying from one of Swashbuckle's unit tests, this :

    [JsonProperty(Required = Required.DisallowNull)]
    public string StringWithRequiredDisallowNull { get; set; }

Should set the property's Nullable flag :

Assert.False(schema.Properties["StringWithRequiredDisallowNull"].Nullable);

And emit nullable:true.

like image 6
Panagiotis Kanavos Avatar answered Nov 09 '22 21:11

Panagiotis Kanavos