0

I have an API which controllers are defined inside another project in a NuGet that I don't have control over, so I can't add attributes to the controller method or classes as it is usually done with SwashBuckle .

I need to add the swagger documentation externally from another project using SwashBuckle API methods, like a custom IDocumentFilter or ISchemaFilter.

The problem comes trying to do the following:

[ProducesResponseType(typeof(MyClass), (int)HttpStatusCode.Accepted)]
public async Task<IActionResult> Get(MyClass request)

I need to do the same but instead of using the method attribute, using SwashBuckle methods, I'm trying using a custom IDocumentFilter with no luck, like so:

public class MyCustomDocFilter : IDocumentFilter
{
  public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
  {
    var pathInfo = swaggerDoc.Paths.FirstOrDefault(p =>...);
    var operationInfo = pathInfo.Value.Operations.First(op => ...);
    var exampleOperationResponse = operationInfo.Value.Responses.First(op => op.Key == "200");
    exampleOperationResponse.Value.Content.Add(MediaTypeNames.Application.Json, new     OpenApiMediaType {
    // Example = new OpenApiString(@"{ ""someProp"": ""someVal""}"),
    Schema = new OpenApiSchema
    {
        Reference = new OpenApiReference
        {
            Id = typeof(MyClass).Name,
            Type = ReferenceType.Schema
        }
    },

  }
}

If I uncomment above's "Example" line, swagger takes it as if the response is a string instead of using the schema for MyClass which is what I need. The code works well in SwaggerUI, the issue is that using the ReDoc UI from Swashbuckle.AspNetCore.ReDoc shows the following:

Bad response format (what I'm getting): enter image description here

Expected good response example format (would require to define the response schema): enter image description here

Lazaro
  • 179
  • 2
  • 12

1 Answers1

0

To add your own response model in response of swagger operation, before that you need to add your model to swagger SchemaRepository, after that you can create new response, with your model included in it.

See code below, my model: ErrorResponse

public class ErrorResponse
{
    public int Code { get; set; }

    public string Detail { get; set; }
}

And my swagger OperationFilter code:

public class YourOperationFilter: IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        // Try to get my model from swagger schema repository
        context.SchemaRepository.TryLookupByType(typeof(ErrorResponse), out var schema);
    
        if (schema is null)
        {
            // Add schema inside if to exclude multiple adding situation
            schema = context.SchemaGenerator.GenerateSchema(typeof(ErrorResponse), context.SchemaRepository);
        }
    
        var content = new Dictionary<string, OpenApiMediaType>()
            {
                {"application/json", new OpenApiMediaType { Schema = schema } }
            };
        
        // Add response
        operation.Responses.Add("500", new OpenApiResponse { Content = content });
    }
}

Add OperationFilter in swagger gen:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSwaggerGen(x =>
    {
        x.OperationFilter<YourOperationFilter>();
    });
}

see swagger result here

David
  • 21
  • 1
  • 2