-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
Deal-breaker for migration. I discovered this while porting my API from using NSwag.
One component schema per type, not distinct schemas based om nullability. And I think this is a part of a bigger story about dealing with nullability.
I think this also affects Minimal APIs.
In this particular case, it seems like nullability is set on a component schema-level and not the schema on on parameter and response-level
This happens because of the action (Test) with return type TestDto
regardless of whether it is nullable or not. So no concern for explicit nullability either.
Following is for OpenAPI 3.
Consider this controller:
[ApiController]
[Route(“[controller]")]
public class StatisticsController : ControllerBase
{
// TestDto corresponds to component schema "TestDto2" with nullable: true
[HttpGet("Test")]
public TestDto Test()
{
return default!;
}
/*
// Not relevant
[HttpGet("Test2")]
public TestDto? Test2()
{
return default!;
}
*/
// TestDto corresponds to component schema "TestDto" (with nullable: false)
[HttpGet("Test3")]
public KeyValuePair<int, TestDto> Test3()
{
return default!;
}
}
Instead of one TestDto schema, it results in two distinct schemas TestDto and TestDto2 where one is nullable.
The response on the operation should be nullable at an operation-level, not at component schema level:
components:
schemas:
TestDto:
required:
- x
type: object
properties:
x:
type: string
TestDto2:
required:
- x
type: object
properties:
x:
type: string
nullable: true <—- THIS IS WHY THE TYPE HAS TWO SCHEMAS:
With the operation being tis:
paths:
/Statistics/Test2:
get:
tags:
- Statistics
responses:
'200':
description: OK
content:
text/plain:
schema:
$ref: '#/components/schemas/TestDto2’
application/json:
schema:
$ref: '#/components/schemas/TestDto2’
text/json:
schema:
$ref: '#/components/schemas/TestDto2’
Expected Behavior
I would expect this operation with the shared component schema, and the nullability set on the operation:
paths:
/Statistics/Test2:
get:
tags:
- Statistics
responses:
'200':
description: OK
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/TestDto'
nullable: true
components:
schemas:
TestDto:
required:
- x
type: object
properties:
x:
type: string
Meaning the use of ”allOf” and ”nullable: true” on the response.
This allows for maximal re-use of DTOs. Not having two otherwise identical schemas that are different in nullability.
Steps To Reproduce
var builder = WebApplication.CreateBuilder();
builder.Services.AddControllers();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapControllers();
app.MapOpenApi();
app.Run();
Exceptions (if any)
No response
.NET Version
9.0.100-rc.2.24474.11
Anything else?
The bigger story would be to write a transformer that deals with nullability for parameters and responses.
I'm on my way prototyping for my own project.