Cliente Standalone de JAX-RS (o cualquier endpoint RESTful)
Si tenemos una aplicación standalone (puede ser un JavaFX, de línea de comandos, batch, etc) que necesite consumir un endpoint hecho en RESTful, por lo general usaríamos algo como esto:
public class RestClient { private static final String REST_URI = "http://localhost:8082/spring-jersey/resources/employees"; private Client client = ClientBuilder.newClient(); public Employee getJsonEmployee(int id) { return client .target(REST_URI) .path(String.valueOf(id)) .request(MediaType.APPLICATION_JSON) .get(Employee.class); } //... }
(Tomado de https://www.baeldung.com/jersey-jax-rs-client)
Lo cual no está mal, pero creo que debería ser lo más transparente posible. ¿Cómo es eso?
Si ven en la línea 13 del código anterior, significa que hay que decirle que haga un
GET
a la petición, además de pasarle el tipo de respuesta y otras cosas más. La cuestión se volvería algo compleja si queremos hacer otras peticiones como POST
, DELETE
, etc.Pues aquí vengo con una solución que encontré revisando la documentación de JAX-RS.
El servidor
Para este ejemplo, he creado un pequeño servidor CRUD en Payara Micro, el cual puedes obtener su código aquí: https://github.com/apuntesdejava/demo-jaxrs-standalone/tree/master/demo-jaxrs-server
El Endpoint principal es este:
@Path("person") @Produces(APPLICATION_JSON) @Consumes(APPLICATION_JSON) @ApplicationScoped public class PersonEndpoint { @Inject private PersonRepository personRepository; @POST public Response create(PersonParam param) { Person p = personRepository.create(param.getName(), param.getEmail()); return Response.ok(p).build(); } @GET public Response list() { List<Person> list = personRepository.findAll(); return Response.ok(list).build(); } @DELETE @Path("{id}") public Response delete(@PathParam("id")long personId){ personRepository.delete(personId); return Response.ok().build(); } }
@POST
create()
para insertar registros@GET
list()
para leer todos los registros@DELETE
delete()
para borrar un registro
Insertando un registro:
Listando los registros:
Borrando ese registro (en mi caso, el 97)
El Cliente
En el cliente tiene que existir un método que luzca igual que la clase del endpoint servidor para que sea "transparente" la invocación.@Path("person") @Produces(APPLICATION_JSON) @Consumes(APPLICATION_JSON) public interface PersonEndpoint { @POST Response create(PersonParam param); @GET Response list(); @DELETE @Path("{id}") Response delete(@PathParam("id") long personId); }Pero esto tiene un tratamiento muy especial: no es una clase, es una interfaz. Aquí es lo divertido ¿cómo es que lo podrá identificar cada petición? Pues esta es la magia del cliente JAX-RS.
Hay varios clientes de JAX-RS, algunos son:
- RestEasy: https://github.com/resteasy/resteasy-examples/tree/3.6.0.Final/jaxrs-2.0/simple-client
- Quarkus: https://quarkus.io/guides/rest-client
- Apache CXF: https://cxf.apache.org/
Aquí usaré el Apache CXF. Independientemente puede usarse cualquier implementación, pero seguirá siendo la misma interfaz. Solo cambia cómo se invoca al Endpoint del Cliente.
Así se construye usando Apache CXF:
PersonEndpoint client = JAXRSClientFactory.create( REST_URI, PersonEndpoint.class, Arrays.asList( new JacksonJaxbJsonProvider() ));
Luego, se llama como si fuera cualquier método "local":
PersonParam param = new PersonParam("persona 1", "abc@mail.com"); //creo los parámetros Response resp = client.create(param); //invoco al endpoint LOG.log(Level.INFO, "status:{0}", resp.getStatusInfo().getReasonPhrase()); //muestro la respuesta if (resp.getStatus() == Response.Status.OK.getStatusCode()) { //si está ok... Person p = resp.readEntity(Person.class); //.. convierto la petición en la entidad que se recibió... LOG.log(Level.INFO, "-> registro insertado:{0}", p.toString()); //... y muestro el contenido }
Si deseamos listar, también se haría lo mismo:
resp = client.list(); //invocamos el método de listado LOG.log(Level.INFO, "status:{0}", resp.getStatusInfo().getReasonPhrase()); //mostramos el resultado... List<Person> list = null; //preparamos nuestra lista que vamos a recibir if (resp.getStatus() == Response.Status.OK.getStatusCode()) { //evaluamos el contenido... si está OK... list = resp.readEntity(new GenericType<List<Person>>() { //... convertimos la petición en el listado }); list.forEach((p) -> { //... y podemos listar el contenido. LOG.log(Level.INFO, "id:{0}\tname:{1}\temail:{2}", new Object[]{p.getPersonId(), p.getName(), p.getEmail()}); }); }
Código fuente
El código fuente para este proyecto se puede encontrar aquí:- https://github.com/apuntesdejava/demo-jaxrs-standalone
- https://bitbucket.org/apuntesdejava/demo-jaxrs-standalone/
Comentarios
Publicar un comentario
Si quieres hacer una pregunta más específica, hazla en los foros que tenemos habilitados en Google Groups
Ah! solo se permiten comentarios de usuarios registrados. Si tienes OpenID, bienvenido! Puedes obtener su OpenID, aquí: http://openid.net/