当前位置: 首页 > 知识库问答 >
问题:

用swagger: GET调用定义一个API,该调用在参数中使用JSON

丰佐
2023-03-14

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

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

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

我看到很多大摇大摆的API都这样做…

我想不出是否有办法用一个JSON参数,用Swagger做一个合适的rest API。当然,您可以将参数定义为一个字符串,并将您编码的JSON传递给它,但是swagger工具不知道它有一个模式/定义。

swagger不能正确记录这种呼叫吗?

共有2个答案

赏高格
2023-03-14

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

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

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

  • 从模型的属性中删除虚张声势创建的参数
  • 添加字符串类型的查询参数

结果在 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<>));
    }
}

注意事项:

    < li >我使用IsAssignableFrom,因为我有从JsonModelBinder派生的类。不继承可以省略 < li >如果您的活页夹不是通用的,您也可以省略GetGenericTypeDefinition < li >此解决方案不检查参数名冲突,尽管如果API符合常识,您就永远不应该检查参数名冲突
汪典
2023-03-14

OpenAPI 2.0不支持查询字符串中的对象,只支持原语值和原语数组。您最多可以将参数定义为< code>type: string,添加一个JSON值的< code>example,并使用< code>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"}'

查询字符串中的JSON可以使用OpenAPI 3.x进行描述。在OAS 3中,查询参数可以是原语、数组以及对象,您可以指定这些参数的序列化方式——将其展开为key=value对,编码为JSON字符串,等等。

对于包含JSON字符串的查询参数,使用Content关键字为JSON数据定义架构

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用户注意:< br > Swagger UI 3 . 23 . 8和Swagger Editor 3.6.34支持带有< code>content的参数。

早期版本的UI/Editor的解决方法:< br >将参数定义为< code>type: string并添加JSON数据的< code>example。您失去了描述查询字符串的JSON模式的能力,但是“尝试一下”将会起作用。

      parameters:
        - in: query
          name: params
          required: true
          schema:
            type: string                    # <-------
          example: '{"id":4,"name":"foo"}'  # <-------
 类似资料:
  • 问题内容: 我可以在python3.2的全局范围内调用嵌套在另一个函数内的函数吗? 这是从外部func1()调用func2()的一种方法吗? 问题答案: 否,除非您返回该函数: 甚至

  • 我在Azure Active Directory中有一个租户场景,其中API1需要使用身份验证调用另一个API2,并且API1是从SPA调用的。 只是将API1中从SPA接收到的用户JWT传递给调用API2进行身份验证是否正确? 类似于:https://github.com/azure-samples/active-directory-dotnet-webapi-onbehalfof

  • 通过io的requestAbs方法调用/调用/使用REST API的vertx实现。vertx。果心http。vertx-core-3.2.0中的HttpClient类。jar导致HTTP错误::302,响应数据为HTML Erro响应。 不确定requestAbs方法的行为,因为没有引发异常,也没有写入任何日志。此外,还随附了使用vertx JAR的此方法的源代码。如果方法实现有bug,是否有问

  • 我是java / kotlin函数式编程的新手,并做了一些练习。只是想知道如何在调用它时传递lambda的参数。例如,在这里调用一些方法,我需要传递一个Int参数。 如何做到这一点?答案可能非常简单,我只是没有在任何地方找到它,在文档中只有列表的例子,在这种情况下答案是清楚的:

  • $this->db->call_function(); 这个方法用于执行一些 CodeIgniter 中没有定义的 PHP 数据库函数,而且 使用了一种平台独立的方式。举个例子,假设你要调用 mysql_get_client_info() 函数,这个函数 CodeIgniter 并不是原生支持的,你可以这样做: $this->db->call_function('get_client_info')

  • 定义函数 在JavaScript中,定义函数的方式如下: function abs(x) { if (x >= 0) { return x; } else { return -x; } } 上述abs()函数的定义如下: function指出这是一个函数定义; abs是函数的名称; (x)括号内列出函数的参数,多个参数以,分隔; { ...