Los 3 clientes de Spring para hacer peticiones REST

Escrito por el .
java planeta-codigo
Enlace permanente Comentarios

El proyecto Spring ofrece hasta 3 clientes o formas diferentes para realizar peticiones a servicios REST. La ventaja de estos clientes es que no requieren de dependencias adicionales si se usa Spring y están integradas con el ecosistema de Spring y Spring Boot.

Spring

El proyecto de Spring ofrece un ecosistema de proyectos y librerías que cubren con casi seguridad cualquier necesidad de una aplicación, y en caso de necesidad siempre es posible recurrir a librerías de terceros. Este es el caso de las librerías OkHttp y Retrofit que son una alternativa a las funcionalidades que ofrece Spring.

Spring es un proyecto que ofrece una enorme cantidad de funcionalidades, prácticamente cualquier cosa que necesite una aplicación Java lo proporciona de alguna. Esto tiene la ventaja de que eligiendo Spring como framework en caso de necesitar en un futuro una nueva funcionalidad es posible elegir la que ofrezca con la ventaja de estar integrada con el ecosistema del framework.

En los microservicios o servicios web que hacen uso de peticiones REST es necesario un cliente http para hacer peticiones a los endpoints de los servicios. aunque desde la versión 11 de Java en el JDK se ofrece un cliente http que puede ser suficiente para muchos casos de uso sin necesidad de librerías adicionales, soporta HTTP/2 y comunicación asíncrona, el cliente del JDK aunque suficiente para muchos casos es algo más básico que otras opciones.

En Java hay varios clientes http, desde el mencionado HttpClient incorporado en Java hasta de terceros como el también conocido Apache HttpCommons y OkHttp. Spring ofrece tres clientes REST.

Independientemente del cliente que se use es deseable poder configurar algunas propiedades del cliente como timeouts de las peticiones, logging, métricas, autenticación y filtros o interceptores para funcionalidades comunes a todas las peticiones.

Clientes REST de Spring

El cliente REST más antiguo que ha ofrecido Spring ha sido RestTemplate siendo superado por WebClient y otra forma de obtener un cliente REST usando una simple interfaz de Java.

Una alternativa de los clientes REST de WebClient y Http Interface con librerías de terceros son OkHttp y Retrofit dependiendo si se quieren añadir dependencias adicionales y si las funcionalidades ofrecidas por los clientes de Spring son suficientes.

Los ejemplos de código hacen peticiones al endpoint del siguiente sencillo servicio que únicamente devuelve un mensaje recibiendo un parámetro en la ruta de la URL de forma opcional.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package io.github.picdodotdev.blogbitix.springrestclients;

...

@RestController
@RequestMapping("/message")
public class DefaultController {

    @GetMapping(value = {"", "/", "/{name}"})
    public String message(@PathVariable(value = "name", required = false) String name) {
        return (name == null || name.isBlank()) ? "Hello World!" : String.format("Hello %s!", name);
    }
}
DefaultController.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
plugins {
	id 'java'
	id 'application'
}

application {
	group = 'io.github.picdodotdev.blogbitix'
	sourceCompatibility = JavaVersion.VERSION_17

	mainClassName = 'io.github.picdodotdev.blogbitix.springrestclients.Main'
}

repositories {
	mavenCentral()
}

dependencies {
	implementation platform('org.springframework.boot:spring-boot-dependencies:3.0.4')

	implementation 'org.springframework.boot:spring-boot-starter'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-webflux'
}
build.gradle

RestTemplate

RestTemplate sigue siendo una forma sencilla de hacer peticiones REST que aún existe por mantener la compatibilidad con el código existente y que aún no se ha actualizado a otros clientes. Está en modo mantenimiento y tiene algunas limitaciones como ser un cliente síncrono y no soportar streaming.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package io.github.picdodotdev.blogbitix.springrestclients;

...

@SpringBootApplication
@EnableWebMvc
public class Main implements CommandLineRunner {

	@Override
	public void run(String... args) {
		restTemplate();
		webClient();
		httpInterface();
	}

	private void restTemplate() {
		RestTemplate restTemplate = new RestTemplate();
		String message1 = restTemplate.getForObject("http://localhost:8080/message/", String.class);
		String message2 = restTemplate.getForObject("http://localhost:8080/message/{name}", String.class, "picodotdev");

		System.out.println("RestTemplate (message1): " + message1);
		System.out.println("RestTemplate (message2): " + message2);
	}

    ...

	public static void main(String[] args) {
		SpringApplication.run(Main.class, args);
	}
}
Main-1.java

WebClient

WebClient es el sustituto moderno de RestTemplate que ofrece Spring incorporando varias mejoras. Soporta comunicación E/S no bloqueante, comunicación asíncrona y streaming, una API con un estilo funcional fluído. Para el código nuevo lo aconsejable es utilizar este cliente.

Este cliente necesita de un cliente http que es el que realiza realmente las peticiones http, entre los soportados está el cliente http de Java. El cliente soporta filtros con los que implementar interceptores para funcionalidades comunes independientemente de la petición.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package io.github.picdodotdev.blogbitix.springrestclients;

...

@SpringBootApplication
@EnableWebMvc
public class Main implements CommandLineRunner {

	...

	private void webClient() {
		ExchangeFilterFunction filter = (ClientRequest request, ExchangeFunction next) -> {
			System.out.println("Filter " + request.url().getPath());
			return next.exchange(request);
		};
		WebClient webClient = WebClient.builder().clientConnector(new JdkClientHttpConnector()).filter(filter).baseUrl("http://localhost:8080").build();

		String message1 = webClient.get().uri("/message/").retrieve().bodyToMono(String.class).block();
		String message2 = webClient.get().uri("/message/{name}",  "picodotdev").retrieve().bodyToMono(String.class).block();

		System.out.println("WebClient (message1): " + message1);
		System.out.println("WebClient (message2): " + message2);
	}

	...

	public static void main(String[] args) {
		SpringApplication.run(Main.class, args);
	}
}
Main-2.java

Http Interface

Retrofit es una librería que permite invocar un servicio REST definiendo el servicio mediante una interfaz de Java, se ha añadido en Spring 6 y Spring Boot 3 para lo que antes había que recurrir al cliente Feign o como una librería de terceros a Retrofit.

En esencia Http Interface permite invocar un servicio REST igual que invocar un método de una interfaz. El desarrollador crea la interfaz que representa el servicio REST y añaden a los métodos anotaciones que permite a la librería construir una implementación que invocada realiza las peticiones al servicio REST. La implementación de la interfaz se crea a través de la clase HttpServiceProxyFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package io.github.picdodotdev.blogbitix.springrestclients;

...

@SpringBootApplication
@EnableWebMvc
public class Main implements CommandLineRunner {

	...

	private void httpInterface() {
		WebClient client = WebClient.builder().clientConnector(new JdkClientHttpConnector()).baseUrl("http://localhost:8080").build();
		HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();

		MessageService messageService = factory.createClient(MessageService.class);
		String message1 = messageService.message();
		String message2 = messageService.message("picodotdev");

		System.out.println("RestTemplate (message1): " + message1);
		System.out.println("RestTemplate (message2): " + message2);
	}

	...
}
Main-3.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package io.github.picdodotdev.blogbitix.springrestclients;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.service.annotation.GetExchange;

public interface MessageService {

    @GetExchange("/message/")
    String message();

    @GetExchange("/message/{name}")
    String message(@PathVariable("name") String name);
}
MessageService.java
1
2
3
4
5
6
7
8
RestTemplate (message1): Hello World!
RestTemplate (message2): Hello picodotdev!
Filter /message/
Filter /message/picodotdev
WebClient (message1): Hello World!
WebClient (message2): Hello picodotdev!
HttpInterface (message1): Hello World!
HttpInterface (message2): Hello picodotdev!
System.out
Terminal

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
./gradlew run


Comparte el artículo: