Chris Pickford
Chris Pickford

Reputation: 8991

Swashbuckle request parameters not working when using custom model binder

I have an ASP.NET Core 3.1 API endpoint configured as follows:

[HttpGet("api/controller/action/{id}")]
public async Task<IActionResult> GetSingle([FromRoute] GetSingleRequest request) {...}

The DTO has a single Guid property:

public class GetSingleRequest
{
  public Guid Id { get; set; }
}

I have configured a custom model binder to bind Guid properties to string values as I'm using a short guid implementation. This is all working fine when testing using Postman.

However, when using Swagger, instead of passing the route parameter as entered, it passes the parameter template, E.g.

GET /api/controller/action/{id}     // Literally constructs the URI with {id}
GET /api/controller/action/abcd1234 // Not the value as entered

I have tried using MapType and ISchemaFilter as follows:

// startup.cs
c.MapType<Guid>(() => new OpenApiSchema {Type = "string", Format = null});
// startup.cs
c.SchemaFilter<GuidSchemaFilter>();

// GuidSchemaFilter.cs
internal class GuidSchemaFilter : ISchemaFilter
  {
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
      if (context.Type != typeof(Guid))
      {
        return;
      }

      schema.Type = "string";
      schema.Format = null;
    }
  }

Neither of these approaches change this odd behaviour.

How can I configure Swagger to pass a string instead of a Guid as part of the URI when I have a custom model binder configured?

Upvotes: 2

Views: 2817

Answers (1)

LouraQ
LouraQ

Reputation: 6881

How can I configure Swagger to pass a string instead of a Guid as part of the URI when I have a custom model binder configured?

In fact, c.MapType<Guid>(() => new OpenApiSchema {Type = "string", Format = null}); this sentence is enough to solve the problem.

The key to the problem is that the parameters in your route are Camel Case: id, and the field in the GetSingleRequest is the Pascal Case: Id.

As the comment, you can add c.DescribeAllParametersInCamelCase(); to make it ignore the problem of case.

  services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API" });
                c.MapType<Guid>(() => new OpenApiSchema { Type = "string", Format = null });
                c.DescribeAllParametersInCamelCase();
            }); 

Or you change the id in the route template to Id.

        [HttpGet("api/controller/action/{Id}")]
        public async Task<IActionResult> GetSingle([FromRoute] GetSingleRequest request) 
        {

            return Ok();
        }

Here is the test result:

enter image description here

Upvotes: 9

Related Questions