Home > Software engineering >  Swashbuckle: Polymorphism not working with external nuget package
Swashbuckle: Polymorphism not working with external nuget package

Time:11-17

In our API we would like to return a object from a external Nuget package when a users makes a call to the endpoint.

This object (Can be viewed here) has a couple of properties. One of them is called Action. This property has as type IPaymentResponseAction but can be a set of different action types (You can see them all over here).

The generated swagger does not know about these actions and doesn't generate the required code. Even with the polymorphism setting set.

    services.AddSwaggerGen(c =>
            {
                c.EnableAnnotations();
                c.UseOneOfForPolymorphism();
            });

Is there a way that i can make these objects show up in my swagger? Maybe with some custom SwaggerGenOptions?

CodePudding user response:

This can be done using the Swashbuckle.AspNetCore.Annotations package. Depending on the API design, you can use one of the following approaches.

Response schema doesn't depend on a response code

This approach takes advantage of using oneOf in the response schema. The idea is to make Swashbuckle generate a response schema that would have oneOf:

responses:
  '200':
    description: Success
    content:
      application/json:
        schema:
          oneOf:
            - $ref: '#/components/schemas/CheckoutAwaitAction'
            - $ref: '#/components/schemas/CheckoutBankTransferAction'
            - $ref: '#/components/schemas/CheckoutDonationAction'
            - $ref: '#/components/schemas/CheckoutOneTimePasscodeAction'
            # ...

Here is what you need to do:

  1. Add UseOneOfForPolymorphism and SelectSubTypesUsing options to your AddSwaggerGen call; make sure your SelectSubTypesUsing resolves IPaymentResponseAction interface to all the desired implementations your API is returning from a controller method:

    services.AddSwaggerGen(c =>
        {
        // ...
    
        c.UseOneOfForPolymorphism();
        c.SelectSubTypesUsing(baseType =>
        {
            if (baseType == typeof(IPaymentResponseAction))
            {
                return new[]
                {
                    typeof(CheckoutAwaitAction),
                    typeof(CheckoutBankTransferAction),
                    typeof(CheckoutDonationAction),
                    typeof(CheckoutOneTimePasscodeAction),
                    // ...
                };
            }
    
            return Enumerable.Empty<Type>();
        });
    
    
  2. Add SwaggerResponse annotation to your controller methods. Specify only the IPaymentResponseAction interface.

    [HttpGet]
    [SwaggerResponse((int)HttpStatusCode.OK, "response description", typeof(IPaymentResponseAction))]
    public IPaymentResponseAction GetPaymentAction()
    {
        // ...
    
    

This will give you the desired schema in Swagger-UI:

swagger-ui response

Please note that Swagger-UI doesn't support the "Example Value" section if the schema has a oneOf definition: it will just show a response sample for the first resolved type in the SelectSubTypesUsing call.

Response schema depends on a response code

It doesn't seem like your case, but I still wanted to mention it as an option.

If the response schema is different for different response codes, you can specify corresponding types directly in the controller:

[HttpPost]
[SwaggerResponse((int)HttpStatusCode.Created, "response description", typeof(CheckoutAwaitAction))]
[SwaggerResponse((int)HttpStatusCode.OK, "response description", typeof(CheckoutBankTransferAction))]
// ...
public IPaymentResponseAction PostPaymentAction()
{
    // ...

  • Related