Swashbuckle override response type
Asked Answered
B

1

7

I have a generic Result<T> response type in my controllers, e.g.

public Result<T> GetSomething()
{
    ...
}

I also have a custom asp.net core filter that returns a Json representation of T

To have swashbuckle generate correct documentation, I have to decorate every method with:

[Produces(typeof(T))]

As this is cumbersome, easily forgotten and error prone, I was looking for a way to automate this.

Now in Swashbuckle you have a MapType, but I can't get a hold of the T in those methods:

services.AddSwaggerGen(c =>
{
    ...
    c.MapType(typeof(Result<>), () => /*can't get T here*/);
};

I was looking at the IOperationFilter but I can't find a way to override the result type in there.

Then there are ISchemaFilter

 public class ResultSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (!context.Type.IsGenericType || !context.Type.GetGenericTypeDefinition().IsAssignableFrom(typeof(Result<>)))
            {
                return;
            }

            var returnType = context.Type.GetGenericArguments()[0];

            //How do I override the schema here ?
            var newSchema = context.SchemaGenerator.GenerateSchema(returnType, context.SchemaRepository);

        }
    }
Blakely answered 15/6, 2021 at 21:52 Comment(0)
P
8

IOperationFilter is the correct choice. Here is an example that changes the response type for OData endpoints.

public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
    //EnableQueryAttribute refers to an OData endpoint.
    if (context.ApiDescription.ActionDescriptor.EndpointMetadata.Any(em => em is EnableQueryAttribute))
    {

        //Fixing the swagger response for Controller style endpoints
        if (context.ApiDescription.ActionDescriptor is ControllerActionDescriptor cad)
        {

            //If the return type is IQueryable<T>, use ODataResponseValue<T> as the Swagger response type.
            var returnType = cad.MethodInfo.ReturnType;
            if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IQueryable<>))
            {
                var actualType = returnType.GetGenericArguments()[0];
                var responseType = typeof(ODataResponseValue<>).MakeGenericType(actualType);

                var schema = context.SchemaGenerator.GenerateSchema(responseType, context.SchemaRepository);
                foreach (var item in operation.Responses["200"].Content)
                    item.Value.Schema = schema;
            }
        }
    }
}

As you can see here, I'm looping through all of the items in operation.Responses["200"].Content, replacing their schema one by one using the GenerateSchema method that you found.

Preoccupied answered 15/11, 2021 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.