SwaggerDiscriminator Attribute: discriminator field moved from paths to components
See original GitHub issueAfter updating from 5.6.3 to 6.x (tested both 6.1.0 and 6.0.7) when using the SwaggerDiscriminator attribute the “discriminator” field moved from paths/<path>/responses/<..>/content/schema
into /components/schemas/BaseType
.
I.e. in the old code we had:
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Foo"
},
{
"$ref": "#/components/schemas/Bar"
}
],
"discriminator": {
"propertyName": "type",
"mapping": {
"Foo": "#/components/schemas/Foo",
"Bar": "#/components/schemas/Bar"
}
}
}
}
}
}
}
now this has become
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Foo"
},
{
"$ref": "#/components/schemas/Bar"
}
]
}
}
}
}
}
// components
"FooBase": {
"required": [
"type"
],
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true,
"readOnly": true
}
},
"additionalProperties": false,
"discriminator": {
"propertyName": "type",
"mapping": {
"Foo": "#/components/schemas/Foo",
"Bar": "#/components/schemas/Bar"
}
}
}
and the discriminator and mapping can only be found under components of the base type. I assume this is an intentional change?
I can see the point of not repeating the discriminator mappings repeatedly, but it seems rather cumbersome to find the discriminator and mapping with the new structure (basically find the common allOf() parent of all the types referenced in oneOf I think? Not sure this would work for more complicated inheritance hierarchies though).
The sample shown at swagger.io has the discriminator under the response part as it was done in the old version though.
Reproduction
Using the basic ASP.NET Core 3.1 template with the following controller:
[ApiController]
[Route("[controller]")]
public class LogsController : ControllerBase
{
[HttpGet]
[ProducesResponseType(typeof(FooBase), StatusCodes.Status200OK)]
public FooBase Get()
{
return new Foo();
}
}
[SwaggerDiscriminator("type")]
[SwaggerSubType(typeof(Foo), DiscriminatorValue = nameof(Foo))]
[SwaggerSubType(typeof(Bar), DiscriminatorValue = nameof(Bar))]
public abstract class FooBase
{
public string Type { get; }
public FooBase(string type)
{
Type = type;
}
}
public class Foo : FooBase
{
public Foo() : base(nameof(Foo)) { }
}
public class Bar : FooBase
{
public Bar() : base(nameof(Bar)) { }
}
and those changes added to the Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// standard template
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1",
new OpenApiInfo
{
Title = "My API - V1",
Version = "v1"
}
);
c.EnableAnnotations(true, true);
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// standard template
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("v1/swagger.json", "My API V1");
});
}
results in different swagger.jsons depending on whether 5.6.3 or 6.1.0 is used.
Swagger.json 5.6.3
{
"openapi": "3.0.1",
"info": {
"title": "My API - V1",
"version": "v1"
},
"paths": {
"/Logs": {
"get": {
"tags": [
"Logs"
],
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Foo"
},
{
"$ref": "#/components/schemas/Bar"
}
],
"discriminator": {
"propertyName": "type",
"mapping": {
"Foo": "#/components/schemas/Foo",
"Bar": "#/components/schemas/Bar"
}
}
}
},
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Foo"
},
{
"$ref": "#/components/schemas/Bar"
}
],
"discriminator": {
"propertyName": "type",
"mapping": {
"Foo": "#/components/schemas/Foo",
"Bar": "#/components/schemas/Bar"
}
}
}
},
"text/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Foo"
},
{
"$ref": "#/components/schemas/Bar"
}
],
"discriminator": {
"propertyName": "type",
"mapping": {
"Foo": "#/components/schemas/Foo",
"Bar": "#/components/schemas/Bar"
}
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Bar": {
"type": "object",
"allOf": [
{
"$ref": "#/components/schemas/FooBase"
}
],
"additionalProperties": false
},
"FooBase": {
"required": [
"type"
],
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true,
"readOnly": true
}
},
"additionalProperties": false
},
"Foo": {
"type": "object",
"allOf": [
{
"$ref": "#/components/schemas/FooBase"
}
],
"additionalProperties": false
}
}
}
}
Swagger.json 6.1.0
{
"openapi": "3.0.1",
"info": {
"title": "My API - V1",
"version": "v1"
},
"paths": {
"/Logs": {
"get": {
"tags": [
"Logs"
],
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Foo"
},
{
"$ref": "#/components/schemas/Bar"
}
]
}
},
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Foo"
},
{
"$ref": "#/components/schemas/Bar"
}
]
}
},
"text/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Foo"
},
{
"$ref": "#/components/schemas/Bar"
}
]
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Bar": {
"type": "object",
"allOf": [
{
"$ref": "#/components/schemas/FooBase"
}
],
"additionalProperties": false
},
"Foo": {
"type": "object",
"allOf": [
{
"$ref": "#/components/schemas/FooBase"
}
],
"additionalProperties": false
},
"FooBase": {
"required": [
"type"
],
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true,
"readOnly": true
}
},
"additionalProperties": false,
"discriminator": {
"propertyName": "type",
"mapping": {
"Foo": "#/components/schemas/Foo",
"Bar": "#/components/schemas/Bar"
}
}
}
}
}
}
Issue Analytics
- State:
- Created 3 years ago
- Reactions:11
- Comments:9
I have submitted a Pull Request #2683 that fixes this bug.
This issue is breaking the openapi typescript fetch client generator and others. Any news on this?.