Contexto
Vamos a decir que tengo una clase de datos simple en 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;
}
}
Nota: en la práctica, lo uso inmutables para generar esto, pero estoy mostrando un POJO aquí en aras de la simplicidad.
Para documentar el modelo de la GET
respuesta, incluso si el tipo de retorno es Response
, puedo refiero a la clase en @ApiOperation
:
@GET
@ApiOperation(response = Person.class)
public Response getPerson() {
return Response.ok(new Person("Julien", 28)).build();
}
Basado en esto, Swagger documentará esto correctamente:
Modelo:
Person { name (string), age (number) }
Valor de ejemplo:
{ "name": "string", "age": 0 }
Para documentar el modelo del POST
cuerpo, utilizo la clase directamente en el código, Swagger lo encuentra y documentos como desee:
@POST
@ApiOperation(response = Person.class)
public Response addPerson(Person newPerson) {
return Response.ok(store.insert(newPerson)).build();
}
Problema
Quiero apoyar actualizaciones parciales también. No puedo utilizar el propio POJO, ya que todos los campos son obligatorios en el POJO, me baso en que para recibir cheques de seguridad y mensajes de error claros cuando JSON no válido se envía a por ejemplo el POST
método.
En mi caso de uso real, mi modelo de datos contiene mapas. Quiero que los usuarios puedan especificar una determinada clave en la actualización y establecer el valor a null
, a los elementos de borrado de un mapas existentes.
Elegí para apoyar PATCH
peticiones en las que el cuerpo se escribe como una llanura JsonNode
. Eso permite que cualquier JSON para ser recibida por mi servidor y que puede aplicar las actualizaciones como deseo.
@PATCH
@Path("/{name}")
@ApiOperation(response = Person.class)
public Response updatePerson(@PathParam("name") String name, JsonNode update) {
return Response.ok(store.update(name, update)).build();
}
Estoy contento con el resultado, excepto que ahora Swagger documenta el modelo de la actualización parcial de las propiedades del JsonNode
objeto de Java:
Modelo:
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) }
Valor de ejemplo:
{ "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 }
Me gustaría especificar en mi código que el modelo es como Person
, de manera que el ejemplo dado en la interfaz de usuario Swagger es más relevante. Yo probé @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();
}
Eso no hace ninguna diferencia. Swagger sigue documenta JsonNode
en sí. La documentación para @ApiImplicitParams
menciona:
Mientras ApiParam está ligada a un parámetro de JAX-RS, método o campo, esto le permite definir manualmente un parámetro de una manera afinado. Esta es la única manera de definir los parámetros utilizando las Servlets u otros entornos no JAX-RS.
Desde que estoy usando JAX-RS, esto podría significar que no puedo usar @ApiImplicitParams
, pero @ApiParam
no proporciona nada para sustituir la clase.
¿Cómo puedo especificar manualmente el modelo de datos de un parámetro de JAX-RS que es detectada por la fanfarronería de forma automática?
La adición de esta respuesta para que sea más bien genérica, para una mejor comprensión de @ApiImplicitParams
.
Usted tendría que utilizar @ApiImplicitParams
para envolver los parámetros que desea guardar en la documentación. @ApiImplicitParam
tiene muchos beneficios no tan evidentes, al igual que para pasar de parámetro cabecera adicional sin agregarlo como un parámetro método o en su caso envoltura de los params con el fin de hacerlos algún sentido.
Para su problema, usted tendría que usar @ApiImplicitParam
junto con el paramType = "body"
que desea realizar cambios en el cuerpo, de manera similar paramType = "head"
si quería cambios en la cabecera.
También puede controlar los campos obligatorios en @ApiImplicitParam
la propiedad required = true/false
.
Como se dijo anteriormente, se puede pasar un parámetro sin tener que en el parámetro método, puede controlar su valor de uso de la propiedad value = "required value"
.
También puede controlar los valores permitidos en @ApiImplicitParam
el uso de valores de coma separados. P.ej. allowableValues = "no-cache, no-store"
.