我正在尝试创建一个合适的REST API,并使用Swagger(2.0)进行记录。
所以,我有一个API调用,它是一个查询,即它没有做任何改变,也没有创建任何东西(幂等和安全)。但它需要传递一个复杂的JSON参数(项目列表,2或3组地址等)。所以我使用URL编码的JSON参数进行GET。这似乎是正确的方法。
我经常看到这样的API,因为这个原因他们以POST作为POST,但这是对POST动词的错误使用。
我看到很多摇摇欲坠的API会这样做......
我无法弄清楚是否有办法使用Swagger使用JSON参数进行正确的休息API。当然,您可以将参数定义为字符串,并将编码后的JSON传递给它,但是swagger工具并不了解它的架构/定义。
招摇是否无法正确记录此类电话?
答案 0 :(得分:4)
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"}'
查询字符串中的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) => {}
我创建了执行以下操作的操作过滤器:
作为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<>));
}
}
注意:
答案 2 :(得分:-1)
我还在努力定义表格参数,这些参数是URL编码的JSON对象,面临与您相同的情况。
彻底浏览Swagger规范会告诉你,这还不支持,但REST API非常需要。
此外,您无法为此类对象定义架构。