使用swagger定义API:在参数

时间:2016-01-15 21:22:46

标签: rest swagger-2.0

我正在尝试创建一个合适的REST API,并使用Swagger(2.0)进行记录。

所以,我有一个API调用,它是一个查询,即它没有做任何改变,也没有创建任何东西(幂等和安全)。但它需要传递一个复杂的JSON参数(项目列表,2或3组地址等)。所以我使用URL编码的JSON参数进行GET。这似乎是正确的方法。

我经常看到这样的API,因为这个原因他们以POST作为POST,但这是对POST动词的错误使用。

我看到很多摇摇欲坠的API会这样做......

我无法弄清楚是否有办法使用Swagger使用JSON参数进行正确的休息API。当然,您可以将参数定义为字符串,并将编码后的JSON传递给它,但是swagger工具并不了解它的架构/定义。

招摇是否无法正确记录此类电话?

3 个答案:

答案 0 :(得分:4)

OpenAPI 2.0(Swagger 2.0)

OpenAPI 2.0不支持查询字符串中的对象,它只支持原始值和基元数组。您可以做的最多是将参数定义为type: string,添加example的JSON值,并使用description来记录JSON对象结构。

swagger: '2.0'
...
paths:
  /something:
    get:
      parameters:
        - in: query
          name: params
          required: true
          description: A JSON object with the `id` and `name` properties
          type: string
          example: '{"id":4,"name":"foo"}'

OpenAPI 3.0

查询字符串中的JSON可以使用OpenAPI 3.0来描述。在OAS 3中,查询参数可以是基元,数组和对象,您可以指定如何序列化这些参数 - 展平为key=value对,编码为JSON字符串,等等。

对于包含JSON字符串的查询参数,请使用content关键字为JSON数据定义schema

openapi: 3.0.1
...

paths:
  /something:
    get:
      parameters:
        - in: query
          name: params
          required: true

          # Parameter is an object that should be serialized as JSON
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string

这对应于以下GET请求(在URL编码之前):

GET /something?params={"id":4,"name":"foo"}

或在URL编码之后:

GET /something?params=%7B%22id%3A4%2C%22name%22%3A%22foo%22%7D


Swagger UI用户注意事项:截至2018年7月,Swagger UI不支持使用content的参数,请参阅issue 4442

如果您需要"尝试一下"支持,解决方法是将参数定义为type: string并添加example JSON数据。您失去了为查询字符串描述JSON模式的能力,但是"尝试一下"会工作的。

      parameters:
        - in: query
          name: params
          required: true
          schema:
            type: string                    # <-------
          example: '{"id":4,"name":"foo"}'  # <-------

答案 1 :(得分:0)

.Net和Swashbuckle(在3.0上测试) 我有一个通用类JsonModelBinder实现IModelBinder接口。该类的用法如下:

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

我创建了执行以下操作的操作过滤器:

  • 从模型的属性中删除由Swashbuckle创建的参数
  • 添加字符串类型的查询参数

作为Swagger的结果,我有一个文本字段,可以在其中插入json和测试请求

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<ControllerParameterDescriptor>()
            .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<string>(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<>));
    }
}

注意:

  • 我使用IsAssignableFrom,因为我有派生自JsonModelBinder的类。如果您不继承,则可以省略
  • 如果您的资料夹不是通用的,您也可以省略GetGenericTypeDefinition
  • 此解决方案不检查参数名称冲突,尽管如果API具有常识,则永远不要使用它

答案 2 :(得分:-1)

我还在努力定义表格参数,这些参数是URL编码的JSON对象,面临与您相同的情况。

彻底浏览Swagger规范会告诉你,这还不支持,但REST API非常需要。

此外,您无法为此类对象定义架构。