Align Optionality in Your C# API with OpenAPI 3.1 Specifications

When developing an Application Programming Interface (API), it’s crucial to maintain consistency between your API implementation and its documentation. What do you do if you’re using C# and OpenAPI 3.1?

Defining Types in OpenAPI 3.1

If you’re using C# for your API and OpenAPI 3.1 for your specification, there are several techniques you can employ to ensure they match up, particularly when it comes to handling null and optional properties.

Define a type as null but not optional.

To define a property as nullable but required in OpenAPI 3.1, you can use the “null” type along with including the property in the “required” list. This would likely be your use case with default C# controllers. Here’s an example:


type: object
properties:
  id:
    type: "integer"
  name:
    type: "string"
  description:
    type: 
      - "string"
      - "null"
required:
  - id
  - name
  - description

Define a type as optional but not null.

To define a property as optional but not nullable, simply omit the property from the “required” list and do not include the “null” keyword as a type. Here’s an example:


type: object
properties:
  id:
    type: "integer"
  name:
    type: "string"
  description:
    type: "string"
required:
  - id
  - name

Define a type as null or optional.

To define a property as both optional and nullable, omit the property from the “required” list and include the “null” type. Here’s an example:


type: object
properties:
  id:
    type: "integer"
  name:
    type: "string"
  description:
    type: 
      - "string"
      - "null"
required:
  - id
  - name

Use $ref with null or optional.

It’s quite common that you have shared types within your API specification. If you want to use a $ref similar to how we allow “string” or “null” above, you will need to use either oneOf or anyOf. In this example, the property is not optional, but it is nullable. Here’s an example:


components:
  schemas:
    Description:
      type: object
      properties:
        height:
          type: "string"
        hair:
          type: "string"

    Account:
      type: object
      properties:
        id:
          type: "integer"
        name:
          type: "string"
        description:
          oneOf: 
            - $ref: "#/components/schemas/Description"
            - "null"
      required:
        - id
        - name
        - description

Pruning Null Values from C# Results

By default, C# API controllers will return all properties of a result object, even if they are null. If you opted for more optional fields in your API, you will need to update your C#. To align your C# API with your OpenAPI 3.1 spec, you can configure your controllers to ignore null values.

Configure JSON serialization options.

One approach is to configure the JSON serialization settings globally to ignore null values. You can do this by configuring the AddJsonOptions in your Startup.cs file:


services.Configure(options =>
{
  options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
});

This will ensure that null values are not included in the API responses across your entire application. Here is a helpful post about achieving this across different dotnet core versions.

Use [JsonIgnore] attribute.

Another way to exclude null values from the API response is by using the [JsonIgnore] attribute on properties that should be omitted when null. Here’s an example:


public IActionResult GetItem(int id)
{
    var item = _repository.GetItem(id);
    return Ok(new {
        id = item.Id,
        name = item.Name,
        description = item.Description ?? JsonIgnore()
    });
}

Maintaining Consistency Between Implementation and Documentation

Use these techniques to define types in your OpenAPI 3.1 specification and prune null values from your C# API results. That way, you can ensure consistency between your implementation and documentation. This makes it easier for developers to understand and use your API effectively.

Conversation

Join the conversation

Your email address will not be published. Required fields are marked *