Reputation: 1954
With the code below I'm trying to mention alternative schemas; which share the same interface, as the type of the response.
Startup.cs
services.AddSwaggerGen(c =>
{
c.UseOneOfForPolymorphism();
});
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
});
Models
public interface IOutput
{
string Discriminator { get; }
}
public class OutputA : IOutput
{
public string Discriminator => GetType().Name;
public string PropA { get; set; }
}
public class OutputB : IOutput
{
public string Discriminator => GetType().Name;
public string PropB { get; set; }
}
Controller
[HttpGet]
[ProducesResponseType(typeof(IOutput), StatusCodes.Status200OK)]
public IActionResult Get()
{
return Ok();
}
I'm expecting both types OutputA
and OutputB
will be listed as return types,
But only IOutput
is mentioned:
Alternatively, If I change the IOutput
from an interface
to a class
or an abstract class
then OutputA
and OutputB
will be listed as valid return types:
Is this not supported due to a RESTFul/API standard?
Or can this be achieved?
This is a .NET Core 2.2
project, using Swashbuckle.AspNetCore v6.2.3
Upvotes: 4
Views: 6765
Reputation: 195
I ran into the problem of swagger gen not including schema for types that implement an interface (works for abstract base class/record). I used the following solution as it is more generic than specifying individual types.
builder.Services.AddSwaggerGen(opts => {
opts.UseOneOfForPolymorphism();
//Needed to generate schema from derived types of an interface (base class/record already supported)
opts.SelectSubTypesUsing(baseT => {
return Assembly.GetAssembly(typeof(<SomeTypeInTheLibYouwant>))?.GetTypes()
.Where(derivedT => baseT.IsAssignableFrom(derivedT));
});
});
Upvotes: 1
Reputation: 1954
Sharing the solution I found, just in case if someone may need it.
The idea is to add the polymorphic relationships explicitly through the AddSwaggerGen()
via the SelectSubTypesUsing()
as:
services.AddSwaggerGen(c =>
{
c.UseOneOfForPolymorphism();
c.SelectSubTypesUsing(baseType =>
{
if (baseType == typeof(IOutput))
{
return new[]
{
typeof(OutputA),
typeof(OutputB)
};
}
return Enumerable.Empty<Type>();
});
});
Upvotes: 10