如何手动记录JAX-RS参数的Swagger数据模型?

时间:2019-05-31 15:02:31

标签: java 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发送到例如JSON时清除错误消息。 POST方法。

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

我选择支持PATCH请求,其中将正文键入为普通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现在使用JsonNode Java对象的属性记录了部分更新的模型:

  

型号:

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
}

我想在我的代码中指定模型类似于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参数的数据模型?

2 个答案:

答案 0 :(得分:1)

我在@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)隐藏具有错误模型的自动生成的版本。

使用上面的代码,文档看上去完全像我想要的一样,并且代码继续正常运行。

谢谢大家的帮助!

答案 1 :(得分:1)

添加此答案,使其对通用@ApiImplicitParams有所了解。

您必须使用@ApiImplicitParams来包装参数,以保存在文档中。 @ApiImplicitParam具有许多不太明显的好处,例如传递额外的标头参数而不将其添加为方法参数,或者在您的情况下包装这些参数以使它们有意义。

对于您的问题,要在正文中进行更改,必须将@ApiImplicitParamparamType = "body"一起使用,如果要更改标题,则必须与paramType = "head"一起使用。

您还可以使用属性@ApiImplicitParam控制required = true/false中的必填字段。

如前所述,您可以传递参数而不必将其包含在方法参数中,可以使用属性value = "required value"控制其值。

您还可以使用逗号分隔的值来控制@ApiImplicitParam中的允许值。例如allowableValues = "no-cache, no-store"