Swashbuckle.aspnetcore: Swagger ignores route parameter constraint

Created on 27 Mar 2019  路  4Comments  路  Source: domaindrivendev/Swashbuckle.AspNetCore

Swashbuckle.AspNetCore 4.0.1

We using route constraint to define some parameters (mainly guid).

This work fine with swagger if parameter defined at method parameter:

[HttpGet("User({id:guid})")]
public async Task<IActionResult> GetUserById(Guid id)

This will produce correct type and format:

"parameters": [
{
"type": "string",
"name": "id",
"in": "path",
"required": true,
"format": "guid"
}
]

But it does not work if method parameter omitted:

[HttpGet("User({id:guid})")]
public async Task<IActionResult> GetUserById()

This will produce type only, but not the format:

"parameters": [
{
"type": "string",
"name": "id",
"in": "path",
"required": true
}
]

Is this by design? How can we workaround this?

PS this is mainly used for custom OData implementation when parameters parsed inside ODataParser

p3

Most helpful comment

For a moment I have found following workaround:

public class GuidParameterFilter : IParameterFilter
    {
        /// <inheritdoc />
        public void Apply(IParameter parameter, ParameterFilterContext context)
        {
            if (context.PropertyInfo == null && 
                parameter is NonBodyParameter nonBodyParam &&
                context.ApiParameterDescription.RouteInfo?.Constraints != null && 
                context.ApiParameterDescription.RouteInfo.Constraints.Any(c => c is GuidRouteConstraint))
            {
                nonBodyParam.Format = "guid";
            }
        }
    }

All 4 comments

For a moment I have found following workaround:

public class GuidParameterFilter : IParameterFilter
    {
        /// <inheritdoc />
        public void Apply(IParameter parameter, ParameterFilterContext context)
        {
            if (context.PropertyInfo == null && 
                parameter is NonBodyParameter nonBodyParam &&
                context.ApiParameterDescription.RouteInfo?.Constraints != null && 
                context.ApiParameterDescription.RouteInfo.Constraints.Any(c => c is GuidRouteConstraint))
            {
                nonBodyParam.Format = "guid";
            }
        }
    }

same here, but for type int.
I also used your workarount until it's fixed in Swagger generation.

I was looking at this issue and came up with something:

//SwaggerGenerator.cs - GenerateParameter(...)

var parameterType = (apiParameter.ModelMetadata != null)
    ? apiParameter.ModelMetadata.ModelType
    : apiParameter.RouteInfo?.Constraints
        .Where(x => RouteConstraintMap.ContainsKey(x?.GetType()))
        .Select(x => RouteConstraintMap[x.GetType()])
        .FirstOrDefault();

var schema = (parameterType != null)
    ? _schemaGenerator.GenerateSchema(parameterType, schemaRepository)
    : new OpenApiSchema { Type = "string" };

(...)

private static readonly Dictionary<Type, Type> RouteConstraintMap = new Dictionary<Type, Type>
{
    { typeof(BoolRouteConstraint), typeof(bool) },
    { typeof(DateTimeRouteConstraint), typeof(DateTime) },
    { typeof(DecimalRouteConstraint), typeof(decimal) },
    { typeof(DoubleRouteConstraint), typeof(double)},
    { typeof(FloatRouteConstraint), typeof(float) },
    { typeof(GuidRouteConstraint), typeof(Guid) },
    { typeof(LongRouteConstraint), typeof(long) }
};

It's seem to do the trick. Now I'm trying to find out how to write a proper test to it. It look like the method CreateActionDescriptor(...) doens麓t generate the constraint parameter. I'll keep looking for the solution but if someone could give me hint it would be nice. Any ideas @domaindrivendev ?

Any update on this? I've got a controller that uses a GUID accountID as part of the route, and it's not in any of the actions directly, but is necessary.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

NinoFloris picture NinoFloris  路  3Comments

vanillajonathan picture vanillajonathan  路  3Comments

m-demydiuk picture m-demydiuk  路  3Comments

engelhardtda picture engelhardtda  路  3Comments

gabeluci picture gabeluci  路  3Comments