Defining an API with swagger: GET call that uses JSON in parameters

前端 未结 2 1693
别那么骄傲
别那么骄傲 2020-12-18 01:24

I am trying to create a proper, REST API, and document it with Swagger (2.0).

So, I have an API call that is a query, ie, it makes no changes and doesn\'t create any

2条回答
  •  一生所求
    2020-12-18 01:53

    For .Net and Swashbuckle (tested on 3.0) I have a generic class JsonModelBinder that implements IModelBinder interface. The class is used like this:

    public IActionResult SomeAction(
            [FromRoute] int id, 
            [FromQuery][ModelBinder(BinderType = typeof(JsonModelBinder))] SomeModelquery query) => {}
    

    I have created Operation filter that does the following:

    • Removes parameters created by Swashbuckle from properties of my model
    • Add query parameter of type string

    As a result in Swagger I have a text field where I can insert json and test requests

    public class JsonModelBinderOperationFilter : IOperationFilter
    {
        public void Apply(Operation operation, OperationFilterContext context)
        {
            if (operation.Parameters == null || context.ApiDescription.HttpMethod != HttpMethod.Get.ToString())
                return;
            //Find json parameters
            var jsonGetParameters = context.ApiDescription.ActionDescriptor.Parameters.Cast()
                .Where(p => p.ParameterInfo.CustomAttributes.Any(c => c.AttributeType == typeof(ModelBinderAttribute) && c.NamedArguments.Any(IsJsonModelBinderType))).ToArray();
    
            if (jsonGetParameters.Length > 0)
            {
                //Select parameters names created by Swagger from json parameters
                var removeParamNames = new HashSet(context.ApiDescription.ParameterDescriptions.Where(d => jsonGetParameters.Any(p => p.Name == d.ParameterDescriptor.Name)).Select(p => p.Name));
                //Create new Swagger parameters from json parameters
                var newParams = jsonGetParameters.Select(p => new NonBodyParameter()
                {
                    In = "query",
                    Name = p.Name,
                    Type = "string",
                    Description = "Json representation of " + p.ParameterType.Name
                });
                //Remove wrong parameters and add new parameters
                operation.Parameters = operation.Parameters.Where(p => p.In != "query" || !removeParamNames.Contains(p.Name)).Concat(newParams).ToList();
            }
        }
    
        private static bool IsJsonModelBinderType(CustomAttributeNamedArgument arg)
        {
            var t = arg.TypedValue.Value as Type;
            return t != null && t.GetGenericTypeDefinition().IsAssignableFrom(typeof(JsonModelBinder<>));
        }
    }
    

    Notes:

    • I use IsAssignableFrom because I have classes derived from JsonModelBinder. You can omit it if you don't inherit
    • You can also omit GetGenericTypeDefinition if your binder is not generic
    • This solution doesn't check for parameter name collision, though you should never have it if the API made with common sense

提交回复
热议问题