Antes de Java 11 consumir un Rest API sin usar una librería de terceros era definitivamente una pesadilla y un desafío. La opción proporcionada por el core de Java era el antiguo y nada sencillo HttpURLConnection. Las librerías de terceros eran la alternativa, pero con Java 11 ahora tenemos el nuevo Api HttpClient que simplifica la tarea y es parte del core de Java.
Http URL Connection
Tal como mencionamos, el problema con HttpURLConnection es que trabaja a bajo nivel, se necesita indicar el método HTTP, headers básicos, interactuar directamente con el Output e Input Streams para enviar o recibir mensajes. Finalmente, se necesita parsear el mensaje manualmente.
//Message to send String jsonInputString = "{'name': 'Adam', 'job': 'Programmer'}"; //Creating the connection HttpURLConnection con = (HttpURLConnection)url.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/json; utf-8"); con.setRequestProperty("Accept", "application/json"); con.setDoOutput(true); //Sending the message try(OutputStream os = con.getOutputStream()) { byte[] input = jsonInputString.getBytes("utf-8"); os.write(input, 0, input.length); } //Getting the response try(BufferedReader br = new BufferedReader( new InputStreamReader(con.getInputStream(), "utf-8"))) { StringBuilder response = new StringBuilder(); String responseLine = null; while ((responseLine = br.readLine()) != null) { response.append(responseLine.trim()); } System.out.println(response.toString()); } int responseCode = con.getResponseCode();
Es increíble la cantidad de lineas para un ejemplo sencillo para enviar y recibir un mensaje, y aún falta parsear la respuesta para obtener un JSON y trabajar con el.
Usando librerías de terceros
Bueno, ya vimos que tan tedioso es usar la clase HttpURLConnection para consumir un Rest API. Es por eso que los desarrolladores Java rara vez la usan, y en su lugar alguna librería es utilizada. Algunos ejemplos de estas librerías:
- Apache Http Connection: Es aún un client http que interactua a bajo nivel, pero es más flexible y sencillo que HttURLConnection. Si gusta conocer más sobre esta librería, ver estos ejemplos.
- Jersey Client: Jersey is la implementación de referencia para JAX-RS (Restful API) en Java. Proporciona su propio cliente para consumir servicios restful facilmente. Una de sus ventajas es que provee suporte para serializar y deserializar XML y JSON en objetos. Ver más…
- Rest Easy Client: Rest Easy is también una implementación para JAX-RS, y su cliente también proporciona un módulos para serializar y deserializar objetos en XML o JSON tal como Jersey. Pero, su mejor característica es que puede generar también un client a partir de una Interface con anotaciones JAX-RS, este módulo funciona como un proxy que genera el código internamente, solamente se crea una instancia de la interface y listo. Les recomiendo ver esta página.
- OkHttp: Es ampliamente usado en el mundo mobile (android). Proporciona una gran cantidad de características como: soporte para conexiones seguras, HTTP2, y es muy sencillo de usar. Ver más…
HttpClient Java 11+
El nuevo HttpClient API está presente desde Java 9, pero como parte de una iniciativa en incubación. En otras palabras, está disponible, pero no oficialmente liberado, y podría tener cambios con la versión oficial.
La meta con el nuevo API HttpClient API es proporcionar una manera estándar de consumir Rest API, usando patrones modernos y mejores prácticas ya aplicados en las librerías de terceros mencionadas anteriomente. Tiene soporte también para conexiones seguras, HTTP2, websockets y request asíncronos. Veamos un ejemplo:
//Message to send String jsonInputString = "{'name': 'Adam', 'job': 'Programmer'}"; HttpClient httpClient = HttpClient.newBuilder().build(); HttpRequest request = HttpRequest.newBuilder() .POST(BodyProcessor.fromString(jsonInputString)) .uri(URI.create("https://mydomain.com/api/books")) .build(); HttpResponse<String> response = httpClient .send(request, BodyHandlers.ofString());
En comparación con el viejo HttpURLConnection, este código luce más simple y claro. Podemos notar que hay 3 conceptos básicos en este API:
- HttpClient: Se encarga de crear la conexión y su configuración. Proxies, Authenticators, executors pools, cookie manager, etc.
- HttpRequest: Es básicamente el request a un URI. Podemos indicar el timeout, headers, si el request es asíncrono o síncrono.
- HttpResponse: Objeto para manejar la respuesta del request. En él se puede ver el status code, body response, headers y más.
Para simplificar la manera de enviar y recibir objetos desde el código se ha introducido BodyPublishers y BodyHandlers.
Body Publishers y Body Handlers
BodyPublisher se encarga de enviar contenido a un request. El API proporciona publishers para String, InputStreams, Files, and ByteArray. Si por alguna razón necesitamos un método POST/PUT/DELETE que no requiere un body, podemos usar HttpRequest.noBody
.
En la otra mano, BodyHandlers están a cargo de la respuesta. El API proporciona algunos Handlers para String, Streams, ByteArray y otros.
Podemos crear nuestros propios BodyPublishers y BodyHandlers, por ejemplo para Serializar y Deserializar un objeto a JSON directamente por medio de implementar las clases classes HttpResponse.BodyHandler
y HttpRequest.BodyPublisher
.
Requests Asíncronos
Esta característica es muy útil, hay muchos casos de uso donde necesitamos que nuestras llamadas no bloqueen el flujo principal. Por ejemplo en un aplicación dirija por eventos o aplicaciones mobiles.
El nuevo HttpClient proporciona 2 formas para hacer un request tal servidor:
- send(…) – synchronously (bloquea y espera la respuesta)
- sendAsync(…) – asynchronously (no espera la respuesta y no bloquea el hilo principal)
Como podemos ver, podríamos utilizar el método sendAsync(...) – el cual retorna un CompletableFeature<HttpResponse> – para procesar request de forma asíncrona.
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://openjdk.java.net/")) .build(); client.sendAsync(request, BodyHandlers.ofString()) .thenApply(response -> {/* do something here */ return response;}) .thenAccept(System.out::println);
Podemos usar los métodos thenApply y thenAccept del objeto CompletableFuture retornado por el método sendAsync(). Si se pregunta cuál es la diferencia entre esos métodos, thenApply es un Supplier que esperar un respuesta como resultado, y thenAccept es un Consumer es cual no espera una respuesta.
Además, se podría user el método whenComplete, para capturar cualquier resultado incluidas Excepciones.
Conclusión
Definivamente no hay mucho que agregar sobre el nuevo HttpClient, si ud está usando Java 11 o superior, no dude en darle una oportunidad. Continuar usando librerías de terceros está bien en las versiones nuevas de Java, pero en mi opinión este nuevo API es suficientemente completo, robusto y sencillo para la mayoría de casos.
Referencias
- https://mkyong.com/java/apache-httpclient-examples/
- https://www.baeldung.com/jersey-jax-rs-client
- https://www.baeldung.com/resteasy-client-tutorial
- https://www.baeldung.com/java-9-http-client