The "required" modifier can help generate correct OpenAPI specs

A simple "required" modifier efficiently solves mandatory property issues in modern C# versions.

Context

Another thing that I recently found out about while working on a project mentioned in this other post is the required modifier.

I needed to set up a simple model for Advertiser in my code with the following properties:

PropertyRequired
NameYes
DescriptionNo
EmailNo
PhoneNo
Contact InstructionsNo

First option

So that’s how I wrote the code for this model’s DTO class the first time:

public class AdvertiserDto : BaseDto
{
    public string? Name { get; set; }
    public string? Description { get; set; }
    public string? Email { get; set; }
    public string? Phone { get; set; }
    public string? ContactInstructions { get; set; }
}

It must either be constructorless or have a parameterless constructor because that is the class that is coming in and going out in the controller’s actions / APIs, so the serializer can create an instance and set the properties’ values.

As a modern C# project, it has nullable types enabled by default at the project level. That means, if I add a non-nullable string property, it must be initialized after leaving the constructor, or the IDE will complain with a warning: Non-nullable property 'Name' is uninitialized. Consider declaring the property as nullable.

And for that reason, I could not make the string? Name be just string Name.

That will definitely work, but will be wrong in the OpenAPI specification that is generated in the API project, showing that the property is optional, but we know it’s not:

The required modifier

Then, I was looking for a better solution for this, with some considerations:

  • I didn’t want to have this property marked as optional.

  • Can’t add parameters to the constructor and set it as non-nullable.

  • The [Required] attribute on a nullable property doesn’t make sense. It would leave the type in the screenshot above as something like:

    • “name: string | nullable [Required]“.
  • I also didn’t want to suppress any warnings.

So I changed it to a non-nullable string property and checked what would be the options given by the IDE and/or ReSharper, and that one caught my attention:

I gave it a chance and the code ended up like this:

public class AdvertiserDto : BaseDto
{
    public required string Name { get; set; }
    public string? Description { get; set; }
// ...

That way, I ended up with the best possible solution:

  • Not using an optional type for nullable.

  • Not needing to add a constructor to initialize the property.

  • Serializer is able to serialize and deserialize the class without any issue.

  • OpenAPI specification gets correctly generated (screenshot below).

Though, every time I instantiate that class by myself, I need to set something to the Name property, like the example below, or it won’t compile.

var advertiser = new AdvertiserDto {
    Name = "Bdvertiser"
};

But anyway, that’s not a problem at all, at least for now.

Conclusion

That’s how I found out about the required modifier, which was introduced in C# at the end of 2022 with C# 11 (and .NET 7). Check the official docs here.

What I mean with “modern C# problems” in the title is that in older C# projects, specially when using .NET Framework, you don’t even have the optional string? type, and the string type is nullable by default. In those situations, something like the [Required] attribute can help.