-
Notifications
You must be signed in to change notification settings - Fork 279
Description
Describe the bug
When using the OpenApiOperation copy constructor to create a new instance from an existing instance, the new instance does not have the responses details from the existing instance's Responses property copied over.
This is preventing the end-to-end scenario we intended the copy-constructor to facilitate from working, i.e. in an ASP.NET Core minimal APIs project, the following API does not correctly have its schema described in Swagger:
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/weatherforecast", (int foo, [FromHeader]string bar) =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi(o => new (o)
{
Summary = "This is the summary",
Description = "This is the description"
});
app.Run();
internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}To Reproduce
Steps to reproduce the current behavior:
- Use NuGet package
Microsoft.OpenApiversion 1.4.0.preview2 - In your program, create an instance of
OpenApiOperationand add anOpenApiResponseinstance to itsResponsesproperty - Create a second instance of
OpenApiOperationusing the copy constructor and pass in the first instance - Inspect the second instance
Expected behavior
The Responses property on the second instance of OpenApiOperation should contain instances of OpenApiResponse for each of the int response code keys and with suitable details from the first instance, at a minimum including the following properties:
DescriptionContentdictionary with an item per media type key with the following properties copied:ExampleExamplesEncoding
Screenshots/Code Snippets
Here's a console program that demonstrates the issue:
using System.Text.Json;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Quibble.CSharp;
var operation1 = new OpenApiOperation
{
Description = "My API description",
Summary = "My API summary",
Tags = new List<OpenApiTag>
{
new() { Name = "Tag 1" },
new() { Name = "Tag 2" }
},
Parameters = new List<OpenApiParameter>
{
new() { Name = "foo", In = ParameterLocation.Path, Required = true,
Description = "The foo parameter", Example = new OpenApiString ("exampleValue") }
},
Responses = new()
{
{
"200",
new()
{
Description = "Success",
Content = new Dictionary<string, OpenApiMediaType>
{
{ "application/json", new() },
{ "text/plain", new() }
}
}
},
{
"400",
new()
{
Description = "Bad Request",
Content = new Dictionary<string, OpenApiMediaType>
{
{ "application/problem+json", new() },
{ "text/plain", new() }
}
}
}
}
};
var operation2 = new OpenApiOperation(operation1);
var operation1Json = JsonSerializer.Serialize(operation1);
var operation2Json = JsonSerializer.Serialize(operation2);
var diffs = JsonStrings.TextDiff(operation1Json, operation2Json);
foreach (var diff in diffs)
{
Console.WriteLine(diff);
}
Console.ReadLine();Outputs:
Type difference at $.RequestBody: null vs an object.
Object difference at $.Responses.
Left only properties: '200' (object), '400' (object).
Additional context
Another way of visualizing the issue.
First instance of OpenApiOperation JSON serialized:
{
"Tags": [
{
"Name": "WebApplication8",
"Description": null,
"ExternalDocs": null,
"Extensions": {},
"UnresolvedReference": false,
"Reference": null
}
],
"Summary": null,
"Description": null,
"ExternalDocs": null,
"OperationId": "GetWeatherForecast",
"Parameters": [],
"RequestBody": null,
"Responses": {
"200": {
"Description": "Success",
"Headers": {},
"Content": {
"application/json": {
"Schema": null,
"Example": null,
"Examples": {},
"Encoding": {},
"Extensions": {}
}
},
"Links": {},
"Extensions": {},
"UnresolvedReference": false,
"Reference": null
}
},
"Callbacks": {},
"Deprecated": false,
"Security": [],
"Servers": [],
"Extensions": {}
}
Second instance of OpenApiOperation JSON serialized:
{
"Tags": [
{
"Name": "WebApplication8",
"Description": null,
"ExternalDocs": null,
"Extensions": {},
"UnresolvedReference": false,
"Reference": null
}
],
"Summary": null,
"Description": null,
"ExternalDocs": null,
"OperationId": "GetWeatherForecast",
"Parameters": [],
"RequestBody": {
"UnresolvedReference": false,
"Reference": null,
"Description": null,
"Required": false,
"Content": null,
"Extensions": null
},
"Responses": {},
"Callbacks": {},
"Deprecated": false,
"Security": [],
"Servers": [],
"Extensions": {}
}