首页 > 解决方案 > 如何手动记录 JAX-RS 参数的 Swagger 数据模型?

问题描述

语境

假设我在 Java 中有一个简单的数据类:

public class Person {
    private final String name;
    private final int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    int String getAge() {
        return age;
    }
}

注意:在实践中,我使用Immutables来生成它,但为了简单起见,我在这里展示了一个POJO 。

为了记录GET响应的模型,即使返回类型是Response,我也可以参考 中的类@ApiOperation

@GET
@ApiOperation(response = Person.class)
public Response getPerson() {
    return Response.ok(new Person("Julien", 28)).build();
}

基于此,Swagger 将正确记录这一点:

模型:

Person {
  name (string),
  age (number)
}

示例值:

{
  "name": "string",
  "age": 0
}

为了记录POST身体的模型,我直接在代码中使用类,Swagger 找到它并根据需要记录它:

@POST
@ApiOperation(response = Person.class)
public Response addPerson(Person newPerson) {
    return Response.ok(store.insert(newPerson)).build();
}

问题

我也想支持部分更新。我不能使用 POJO 本身,因为 POJO 中的所有字段都是必需的,我依靠它来获得安全检查并在将无效 JSON 发送到例如该POST方法时清除错误消息。

在我的实际用例中,我的数据模型包含地图。我希望用户能够在更新中指定某个键并将值设置为null, 以从现有地图中删除元素。

我选择支持PATCH将正文键入为 plain 的请求JsonNode。这允许我的服务器接收任何 JSON,并且我可以根据需要应用更新。

@PATCH
@Path("/{name}")
@ApiOperation(response = Person.class)
public Response updatePerson(@PathParam("name") String name, JsonNode update) {
    return Response.ok(store.update(name, update)).build();
}

我对结果很满意,除了 Swagger 现在用JsonNodeJava 对象的属性记录部分更新的模型:

模型:

JsonNode {
  array (boolean, optional),
  null (boolean, optional),
  number (boolean, optional),
  float (boolean, optional),
  pojo (boolean, optional),
  valueNode (boolean, optional),
  containerNode (boolean, optional),
  object (boolean, optional),
  missingNode (boolean, optional),
  nodeType (string, optional) = ['ARRAY', 'BINARY', 'BOOLEAN', 'MISSING', 'NULL', 'NUMBER', 'OBJECT', 'POJO', 'STRING'],
  integralNumber (boolean, optional),
  floatingPointNumber (boolean, optional),
  short (boolean, optional),
  int (boolean, optional),
  long (boolean, optional),
  double (boolean, optional),
  bigDecimal (boolean, optional),
  bigInteger (boolean, optional),
  textual (boolean, optional),
  boolean (boolean, optional),
  binary (boolean, optional)
}

示例值:

{
  "array": true,
  "null": true,
  "number": true,
  "float": true,
  "pojo": true,
  "valueNode": true,
  "containerNode": true,
  "object": true,
  "missingNode": true,
  "nodeType": "ARRAY",
  "integralNumber": true,
  "floatingPointNumber": true,
  "short": true,
  "int": true,
  "long": true,
  "double": true,
  "bigDecimal": true,
  "bigInteger": true,
  "textual": true,
  "boolean": true,
  "binary": true
}

我想在我的代码中指定模型是 like Person,以便 Swagger UI 中给出的示例更相关。我确实尝试过@ApiImplicitParams

@PATCH
@Path("/{name}")
@ApiOperation(response = Person.class)
@ApiImplicitParams({
  @ApiImplicitParam(name = "update", dataTypeClass = Person.class)
})
public Response updatePerson(@PathParam("name") String name, JsonNode update) {
    return Response.ok(store.update(name, update)).build();
}

那没有任何区别。Swagger 仍然记录JsonNode自己。@ApiImplicitParams提及的文档:

虽然ApiParam绑定到 JAX-RS 参数、方法或字段,但这允许您以微调的方式手动定义参数。这是使用 Servlet 或其他非 JAX-RS 环境时定义参数的唯一方法。

由于我使用的是 JAX-RS,这可能意味着我不能使用@ApiImplicitParams,但@ApiParam不提供任何东西来覆盖该类。

如何手动指定 Swagger 自动检测到的 JAX-RS 参数的数据模型?

标签: javaswagger

解决方案


我走在正确的轨道上@ApiImplicitParam,我想我现在按照我想要的方式工作了:

@PATCH
@Path("/{name}")
@ApiOperation(response = Person.class)
@ApiImplicitParams({
  @ApiImplicitParam(paramType = "body", dataTypeClass = ExchangeConfiguration.class)
})
public Response updatePerson(@PathParam("name") String name, @ApiParam(hidden = true) JsonNode update) {
    return Response.ok(store.update(name, update)).build();
}

配置名称不是强制性的,但paramType似乎是必需的。使用paramType = "body"使 Swagger 正确记录隐式参数。这将导致尸体被记录两次;我们可以使用错误的模型隐藏自动生成的版本@ApiParam(hidden = true)

使用上面的代码,文档看起来完全符合我的要求,并且代码继续正常运行。

感谢大家的帮助!


推荐阅读