El documento openAPI incluye todas las entradas de ProducesResponseType por código de estado

ASP.NET Core 11 cambia cómo el paso de recopilación de metadatos de MVC ApiExplorer y el de Minimal API gestionan varias declaraciones de [ProducesResponseType] o Produces para el mismo código de estado. Anteriormente, se eliminaban todas las declaraciones salvo una para cada código de estado antes de que se generara el documento OpenAPI. A partir de ASP.NET Core 11, se conservan todas las declaraciones y el documento OpenAPI generado refleja todos los tipos de contenido y esquema declarados para cada código de estado.

Versión introducida

.NET 11

Comportamiento anterior

Tanto para los controladores MVC como para las API mínimas, solo sobrevivió uno ApiResponseType para cada código de estado. Los atributos [ProducesResponseType] adicionales o las llamadas a .Produces<T>(...) con el mismo código de estado sobrescribieron de forma silenciosa la entrada anterior. Por lo tanto, el documento OpenAPI generado contenía una única variante de respuesta por código de estado, incluso cuando el desarrollador declaró varios.

Por ejemplo, con el siguiente endpoint de Minimal API:

app.MapGet("/items/{id}", (int id) => /* ... */)
    .Produces<Product>(200)
    .Produces<Customer>(200, "text/xml");

El documento openAPI generado contiene solo la Customer variante para el estado 200; la Product variante se quitó silenciosamente.

El mismo comportamiento de sobrescritura aplicado a los controladores:

[ProducesResponseType(typeof(Foo), 200, "application/json")]
[ProducesResponseType(typeof(Bar), 200, "text/xml")]
public IActionResult Get() => /* ... */;

Solo la Bar / text/xml variante sobrevivió en el documento openAPI.

Nuevo comportamiento

A partir de ASP.NET Core 11, se conservan todos los tipos de respuesta declarados para el mismo código de estado y se emiten en el documento OpenAPI generado. En el ejemplo de API mínima anterior, la responses["200"] entrada ahora contiene el application/json esquema (para Product) y el text/xml esquema (para Customer). En el ejemplo del controlador, se emiten tanto el application/json esquema (para Foo) como el text/xml esquema (para Bar). Cuando varias declaraciones comparten el mismo código de estado y el mismo tipo de contenido, pero declaran tipos diferentes, el documento openAPI representa el esquema de respuesta como una anyOf composición de los tipos declarados (un valor válido con al menos uno de ellos satisface el esquema).

Los tipos de contenido de nivel [Produces] de controlador siguen aplicándose como el tipo de contenido predeterminado compartido para las entradas que no especifican sus propias. Las declaraciones de nivel de atributo en una acción tienen prioridad sobre las declaraciones de nivel de controlador con el mismo código de estado.

Tipo de cambio disruptivo

Este es un cambio de comportamiento.

Motivo del cambio

Eliminar todas las variantes de respuesta declaradas salvo una produjo documentos OpenAPI incompletos y sorprendió a los usuarios, que esperaban que cada llamada a [ProducesResponseType] o .Produces<T>(...) se reflejara en el esquema generado. El nuevo comportamiento coincide con la intención indicada por el desarrollador y es coherente con el modo en que OpenAPI representa varios tipos de contenido por código de estado. Para obtener más información, vea dotnet/aspnetcore#65650.

La mayoría de las aplicaciones se benefician del nuevo comportamiento sin cambios en el código. Compruebe que:

  • Los consumidores de OpenAPI de bajada (generadores de código como NSwag, OpenAPI Generator o Kiota; pruebas de contrato; compilaciones del SDK de cliente) controlan varias variantes de respuesta por código de estado. La mayoría de los generadores lo hacen, pero el código de cliente generado ahora puede exponer tipos adicionales o un tipo de retorno de unión, donde antes solo exponía un único tipo.
  • Las pruebas de instantáneas comparadas con el documento OpenAPI generado se actualizan para que contemplen las entradas adicionales.
  • Se quitan las declaraciones duplicadas o obsoletas [ProducesResponseType] enmascaradas previamente por el comportamiento de sobrescritura. Audite los puntos de conexión que tienen varias declaraciones para el mismo código de estado y quita los que ya no se aplican.

Si desea expresamente la forma de una sola variante anterior para un punto de conexión específico, elimine las declaraciones redundantes del punto de conexión en lugar de utilizar el comportamiento de sobrescritura.

Las APIs afectadas