简体   繁体   中英

Swashbuckle SchemaFilter for api operation parameters

I have succesfully created ISchemaFilter to extend swagger.json enum property definitions for code generation purposes as described here . Here is my current SchemaFilter.Apply method:

public void Apply(Schema schema, SchemaFilterContext context)
{
    if (context.SystemType.IsEnum)
    {
        var names = Enum.GetNames(context.SystemType);
        var values = Enum.GetValues(context.SystemType);
        var desc = "";

        foreach (var value in values)
        {
            var intValue = Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
            desc += $"{intValue}={value},";
        }
        desc = desc.TrimEnd(',');
        schema.Extensions.Add("x-enumNames", names);
        schema.Extensions["description"] = desc;
    }
}

SchemaFilter works properly on my model definitions where model class has member with enum type. Following there is example of output: resolution -field, which is enum type, notice custom x-enumNames and modified description fields:

resolution: {
    format: "int32",
    enum: [
        1,
        2,
        3,
        4
    ],
    type: "integer",
    x-enumNames: [
        "Hour",
        "Day",
        "Month",
        "Year"
    ],
    description: "1=Hour,2=Day,3=Month,4=Year"
}

Problem is that SchemaFilter does not extend enum types which are in operation parameters . For example following api-method has parameter resolution :

public async Task<ActionResult<ReturnType>> GetData(Models.ResolutionEnum resolution)

And this produces following operation parameter definition to swagger.json (notice missing x-EnumNames ):

{
    name: "resolution",
    in: "query",
    required: true,
    type: "integer",
    format: "int32",
    enum: [
        1,
        2,
        3,
        4
    ]
}

Is there any way mechanism to extend swagger enum-schemas which are part of method parameters?

Try with an IDocumentFilter, I have injected x-stuff using it, here is a sample:

public class InjectXStuff : IDocumentFilter
{
    public void Apply(SwaggerDocument s, DocumentFilterContext c)
    {
        PathItem path = s.Paths.Where(x => x.Key.Contains("Values")).First().Value;
        path.Post.Parameters.FirstOrDefault().Extensions.Add("x-stuff", "123456");
    }
}

the problem there is that you need to know the path in advanced, not sure if there is a pattern you can use in your code to identify those that are enums...

Thank to another answer under this question, I found that there are multiple extension points in Swashbuckle.AspNetCore.SwaggerGen namespace. IParameterFilter is just what I want, and I was able to inject x-enumNames to method parameter definitions.

Following is parameter filter which I made:

public class ModifyParametersFilter : IParameterFilter
{
    public void Apply(IParameter parameter, ParameterFilterContext context)
    {
        var type = context.ParameterInfo?.ParameterType;
        if (type == null)
            return;
        if (type.IsEnum)
        {
            var names = Enum.GetNames(type);
            var values = Enum.GetValues(type);
            var desc = "";

            foreach (var value in values)
            {
                var intValue = Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
                desc += $"{intValue}={value},";
            }
            desc = desc.TrimEnd(',');
            if (!parameter.Extensions.ContainsKey("x-enumNames"))
                parameter.Extensions.Add("x-enumNames", names);
        }
    }
}

As other filters, this can be activated in Startup.cs with following snippet:

services.AddSwaggerGen(c =>
{
    ..
    c.ParameterFilter<ModifyParametersFilter>();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM