Skip to content

Model nullable types using allOf in OpenAPI schema #63301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

captainsafia
Copy link
Member

This PR updates the schema generation logic to use allOf schemas with nullable to model nullable types in responses, request bodies, and properties. This allows us to emit singular unannotated types into components.schemas and mark them as nullabe at the site where they are used.

Before/After Examples

Request Bodies

Before (union type):

{
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Todo" // Todo is ["object", "null"]
        }
      }
    }
  }
}

After (allOf approach):

  {
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "allOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Todo" // Todo is "type": "object"
              }
            ]
          }
        }
      }
    }
  }

Properties

Before:

  {
    "properties": {
      "secondaryUser": {
        "$ref": "#/components/schemas/RefProfile" // RefProfile is ["object", "null"]
      }
    }
  }

After:

  {
    "properties": {
      "secondaryUser": {
        "allOf": [
          {
            "type": "null"
          },
          {
            "$ref": "#/components/schemas/RefProfile" // RefProfile is "type": "object"
          }
        ]
      }
    }
  }

Responses

Before:

  {
    "responses": {
      "200": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/SomeModel"
            }
          }
        }
      }
    }
  }

After:

  {
    "responses": {
      "200": {
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                { "type": "null" },
                { "$ref": "#/components/schemas/SomeModel" }
              ]
            }
          }
        }
      }
    }
  }

The implementation uses NullabilityInfoContext to detect nullability for the following .NET runtime elements and their related OpenAPI concents

The implementation uses NullabilityInfoContext to determine nullability for:

  • Method parameters (via ParameterInfo) which map to request parameters
  • Method return types (via ReturnParameter) which map to response types
  • Properties (via PropertyInfo) which map to properties within complex types

There are some scenarios where it is impossible to determine the nullability of a type at runtime given runtime restrictions. In those cases, we emit a non-nullable schemas. For example, nullability info cannot be resolved for reference types as array element types:

// This will still encode as non-nullable even though declared as string?[]
app.MapGet("/", (string?[] inputs) => { });

@github-actions github-actions bot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Aug 18, 2025
@martincostello martincostello added feature-openapi area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Aug 18, 2025
@captainsafia captainsafia marked this pull request as ready for review August 18, 2025 15:21
@Copilot Copilot AI review requested due to automatic review settings August 18, 2025 15:21
@captainsafia captainsafia requested a review from a team as a code owner August 18, 2025 15:21
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR updates the OpenAPI schema generation logic to use allOf schemas with nullable types to model nullable types in responses, request bodies, and properties. This approach allows generating clean, unannotated component schemas while handling nullability at usage sites.

  • Updates schema generation to use allOf with a null type and a reference to the base schema for nullable types
  • Replaces the previous union type approach (["object", "null"]) with allOf containing { "type": "null" } and the base schema reference
  • Uses NullabilityInfoContext to detect nullability for method parameters, return types, and properties

Reviewed Changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
OpenApiSchemaReferenceTransformerTests.cs Updates test assertions to verify allOf nullable schema structure instead of union types
OpenApiSchemaService.ResponseSchemas.cs Adds comprehensive tests for nullable response schemas using allOf pattern
OpenApiSchemaService.RequestBodySchemas.cs Adds tests for nullable request body parameters with allOf verification
OpenApiSchemaService.PropertySchemas.cs New test file for nullable property schemas using allOf or direct null type inclusion
OpenApiSchemaService.ParameterSchemas.cs Updates parameter schema tests and adds nullable complex type tests
Snapshot files Updates expected OpenAPI document outputs to reflect new allOf nullable schema format
OpenApiSchemaService.cs Adds logic to wrap nullable properties with allOf and prune null types from componentized schemas
OpenApiDocumentService.cs Updates response and request body generation to apply nullable wrappers
OpenApiConstants.cs Adds constant for nullable property metadata
OpenApiJsonSchema.Helpers.cs Adds support for reading nullable property metadata
TypeExtensions.cs Adds methods to determine nullability for responses, requests, and properties
OpenApiSchemaExtensions.cs New extension methods to create allOf nullable wrappers
JsonTypeInfoExtensions.cs Updates schema reference ID generation for nullable value types
JsonNodeSchemaExtensions.cs Updates nullability handling and adds logic to prune null types from componentized schemas
MapSchemasEndpoints.cs Adds sample endpoints demonstrating nullable schema behavior

@captainsafia captainsafia changed the base branch from main to release/10.0-rc1 August 18, 2025 16:15
@captainsafia captainsafia changed the base branch from release/10.0-rc1 to main August 18, 2025 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-openapi
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants