SpringBoot
Tutorial SpringBoot: Clientes RestTemplate y RestClient
Aprende a usar RestTemplate y RestClient y sus diferencias en Spring Boot para realizar peticiones http a API REST externas y consumir datos desde backend.
Aprende SpringBoot GRATIS y certifícateQué son y qué diferencias hay entre RestTemplate y RestClient
En el desarrollo de aplicaciones con Spring Boot, es común necesitar consumir servicios externos mediante peticiones HTTP a APIs REST. Para facilitar esta tarea, Spring ofrece herramientas como RestTemplate y RestClient, que actúan como clientes HTTP dentro de nuestras aplicaciones.
RestTemplate ha sido durante mucho tiempo la clase estándar para realizar peticiones HTTP de forma síncrona en aplicaciones Spring. Permite ejecutar operaciones HTTP como GET, POST, PUT y DELETE de manera sencilla. Un ejemplo de su uso sería:
RestTemplate restTemplate = new RestTemplate();
String respuesta = restTemplate.getForObject("https://api.ejemplo.com/datos", String.class);
Por otro lado, RestClient es la solución más moderna que proporciona Spring para interactuar con servicios REST. Introducido en versiones recientes, RestClient ofrece una API fluida y más flexible que se adapta mejor a las necesidades actuales del desarrollo en Java. Un ejemplo de uso es:
RestClient restClient = RestClient.create();
String respuesta = restClient.get()
.uri("https://api.ejemplo.com/datos")
.retrieve()
.body(String.class);
Una diferencia clave entre ambas herramientas es el enfoque en su diseño. RestTemplate sigue un estilo imperativo clásico, mientras que RestClient adopta un estilo más funcional y fluido. Esto permite que RestClient se integre de manera más natural con las características modernas de Java y facilite la construcción de peticiones más complejas de forma concisa.
Además, RestClient ofrece una mejor extensibilidad y personalización. Permite configurar aspectos avanzados como cabeceras personalizadas, autenticación, serialización y deserialización de datos, y manejo detallado de errores. Esto se logra mediante una API que encadena métodos y mejora la legibilidad del código.
En términos de rendimiento, RestClient está diseñado para trabajar de manera eficiente con las funcionalidades reactivas de Spring, como WebFlux. Aunque RestTemplate puede usarse en entornos reactivos, no está optimizado para ello, lo que puede resultar en un rendimiento subóptimo en aplicaciones que requieren alta concurrencia y escalabilidad.
Otra diferencia importante es el soporte y la evolución futura. RestTemplate está en vías de ser reemplazado y puede que no reciba nuevas actualizaciones importantes. RestClient, al ser la solución más reciente, cuenta con el respaldo activo de la comunidad de Spring y se espera que se siga desarrollando y mejorando en versiones futuras.
Es relevante mencionar que RestClient facilita el manejo de entidades de forma genérica y permite una mayor flexibilidad en la gestión de tipos de respuesta, lo que simplifica el trabajo con diferentes formatos de datos y servicios externos que puedan tener comportamientos variados.
Aunque ambos permiten realizar peticiones HTTP en aplicaciones Spring, RestClient ofrece una serie de ventajas y mejoras significativas respecto a RestTemplate. La adopción de RestClient en nuevos proyectos es recomendable para aprovechar las mejoras en diseño, eficiencia y soporte a largo plazo que ofrece esta herramienta.
Uso de RestTemplate para peticiones HTTP de API REST externas
Para utilizar RestTemplate en un proyecto Spring Boot 3, es necesario declararlo como un componente gestionado por el contenedor de Spring. Esto se logra mediante la configuración de un bean en una clase de configuración:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Una vez configurado, se puede inyectar el RestTemplate en cualquier componente de la aplicación utilizando la anotación @Autowired
:
@Service
public class ApiService {
private final RestTemplate restTemplate;
public ApiService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// Métodos que utilizan restTemplate
}
Para realizar una petición GET y obtener un recurso desde una API externa, se puede utilizar el método getForObject
o getForEntity
de RestTemplate. Por ejemplo:
String url = "https://api.ejemplo.com/usuarios/1";
Usuario usuario = restTemplate.getForObject(url, Usuario.class);
En este ejemplo, se está obteniendo un objeto Usuario desde la URL especificada. Es importante que la clase Usuario esté correctamente mapeada a la estructura de datos que devuelve la API externa.
Para enviar datos a través de una petición POST, se utiliza el método postForObject
:
String url = "https://api.ejemplo.com/usuarios";
Usuario nuevoUsuario = new Usuario("Juan", "Pérez", "juan.perez@example.com");
Usuario resultado = restTemplate.postForObject(url, nuevoUsuario, Usuario.class);
Aquí, se envía un objeto Usuario a la API externa para crear un nuevo recurso. El resultado es el objeto creado, que puede incluir información adicional proporcionada por el servidor.
Si es necesario establecer cabeceras HTTP personalizadas, como autenticación o tipo de contenido, se pueden utilizar las clases HttpHeaders y HttpEntity:
String url = "https://api.ejemplo.com/usuarios";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth("token_de_acceso");
Usuario nuevoUsuario = new Usuario("María", "López", "maria.lopez@example.com");
HttpEntity<Usuario> request = new HttpEntity<>(nuevoUsuario, headers);
ResponseEntity<Usuario> response = restTemplate.postForEntity(url, request, Usuario.class);
En este caso, se está enviando una petición POST con cabeceras personalizadas, incluyendo un token de autenticación Bearer.
Para manejar peticiones PUT y actualizar recursos existentes, se utiliza el método put
:
String url = "https://api.ejemplo.com/usuarios/1";
Usuario usuarioActualizado = new Usuario("Juan", "Pérez González", "juan.perez@example.com");
restTemplate.put(url, usuarioActualizado);
La eliminación de recursos mediante una petición DELETE se realiza con el método delete
:
String url = "https://api.ejemplo.com/usuarios/1";
restTemplate.delete(url);
Es común que las APIs externas requieran parámetros en las URLs o en el cuerpo de la petición. RestTemplate permite pasar parámetros de forma sencilla usando templates y mapas de valores:
String url = "https://api.ejemplo.com/usuarios/{id}";
Map<String, String> params = new HashMap<>();
params.put("id", "1");
Usuario usuario = restTemplate.getForObject(url, Usuario.class, params);
Además, RestTemplate soporta el uso de interceptores para manipular las peticiones y respuestas. Esto es útil para implementar funcionalidades transversales como el logueo o la modificación dinámica de cabeceras:
restTemplate.getInterceptors().add((request, body, execution) -> {
request.getHeaders().add("X-Custom-Header", "ValorPersonalizado");
return execution.execute(request, body);
});
Para manejar errores y excepciones durante las peticiones, se puede utilizar un ResponseErrorHandler personalizado:
restTemplate.setErrorHandler(new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return response.getStatusCode().isError();
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// Lógica de manejo de errores
}
});
Si se requiere configurar aspectos más avanzados, como el manejo de timeout o la gestión de conexiones, es posible personalizar el ClientHttpRequestFactory:
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(Duration.ofSeconds(10));
factory.setReadTimeout(Duration.ofSeconds(30));
RestTemplate restTemplate = new RestTemplate(factory);
En este ejemplo, se establecen tiempos de espera para la conexión y la lectura de datos, lo cual es esencial para aplicaciones que interactúan con servicios externos y necesitan garantizar una resiliencia adecuada.
Para finalizar, es importante recordar que RestTemplate trabaja de forma síncrona y bloqueante. Si la aplicación requiere un manejo asíncrono o reactivo, se debe considerar el uso de otras alternativas como WebClient.
Utilizar RestTemplate correctamente permite que las aplicaciones Spring Boot 3 consuman servicios externos de manera eficiente, manteniendo un código limpio y fácil de mantener. La flexibilidad que ofrece en la configuración y personalización facilita su adaptación a diferentes escenarios y requisitos específicos de las APIs con las que se interactúa.
Uso de RestClient para peticiones HTTP de API REST externas
El RestClient es una herramienta moderna proporcionada por Spring Framework para facilitar la realización de peticiones HTTP a APIs REST externas. Con una API más fluida y flexible que su predecesor RestTemplate, RestClient permite construir y ejecutar peticiones de manera concisa y eficiente.
Para utilizar RestClient en un proyecto de Spring Boot 3, es necesario configurar un bean que lo provea. A diferencia de RestTemplate, la instancia de RestClient se crea mediante un builder, lo que permite una configuración más granular:
@Configuration
public class RestClientConfig {
@Bean
public RestClient restClient() {
return RestClient.builder()
.baseUri("https://api.ejemplo.com")
.build();
}
}
En este ejemplo, se establece una URI base para todas las peticiones, facilitando la construcción de URLs relativas en las operaciones posteriores.
Una vez configurado, se puede inyectar el RestClient en los componentes necesarios utilizando la anotación @Autowired
o por inyección de constructor:
@Service
public class ApiService {
private final RestClient restClient;
public ApiService(RestClient restClient) {
this.restClient = restClient;
}
// Métodos que utilizan restClient
}
Para realizar una petición GET y obtener un recurso desde una API externa, se utiliza el método get()
del RestClient, seguido de la especificación del URI y el tipo de respuesta esperado:
public Usuario obtenerUsuario(Long id) {
return restClient.get()
.uri("/usuarios/{id}", id)
.retrieve()
.body(Usuario.class);
}
En este caso, se está solicitando el usuario con el identificador proporcionado, y el resultado se mapea directamente a un objeto Usuario.
Para enviar datos mediante una petición POST, el RestClient permite construir la petición especificando el cuerpo y el tipo de respuesta:
public Usuario crearUsuario(Usuario nuevoUsuario) {
return restClient.post()
.uri("/usuarios")
.body(nuevoUsuario)
.retrieve()
.body(Usuario.class);
}
Aquí, se está creando un nuevo usuario enviando los datos en el cuerpo de la petición y esperando como respuesta el usuario creado.
Si es necesario actualizar un recurso existente mediante una petición PUT, se utiliza el método put()
de manera similar:
public void actualizarUsuario(Long id, Usuario usuarioActualizado) {
restClient.put()
.uri("/usuarios/{id}", id)
.body(usuarioActualizado)
.retrieve()
.toBodilessEntity();
}
En este ejemplo, se envía el objeto usuarioActualizado al endpoint correspondiente, sin esperar un cuerpo en la respuesta.
Para eliminar un recurso con una petición DELETE, se utiliza el método delete()
:
public void eliminarUsuario(Long id) {
restClient.delete()
.uri("/usuarios/{id}", id)
.retrieve()
.toBodilessEntity();
}
El RestClient permite configurar cabeceras HTTP y parámetros de consulta de manera sencilla. Por ejemplo, para agregar una cabecera de autenticación:
public List<Usuario> listarUsuarios(String token) {
return restClient.get()
.uri("/usuarios")
.header("Authorization", "Bearer " + token)
.retrieve()
.body(new ParameterizedTypeReference<List<Usuario>>() {});
}
En este caso, se está añadiendo una cabecera Authorization con un token Bearer, y se espera una lista de usuarios como respuesta.
Cuando se requiere enviar parámetros en la URL o en los parámetros de consulta, el RestClient permite especificarlos directamente en el método uri()
:
public List<Usuario> buscarUsuarios(String nombre, String email) {
return restClient.get()
.uri(uriBuilder -> uriBuilder
.path("/usuarios/buscar")
.queryParam("nombre", nombre)
.queryParam("email", email)
.build())
.retrieve()
.body(new ParameterizedTypeReference<List<Usuario>>() {});
}
Este ejemplo muestra cómo construir una URI con parámetros de consulta dinámicos utilizando un UriBuilder.
El manejo de respuestas y su conversión a objetos Java es flexible en RestClient. Si se requiere acceder directamente al ResponseEntity para obtener detalles como el código de estado o las cabeceras, se puede utilizar:
public ResponseEntity<Usuario> obtenerUsuarioConDetalles(Long id) {
return restClient.get()
.uri("/usuarios/{id}", id)
.retrieve()
.toEntity(Usuario.class);
}
Para configurar timeout o establecer otras propiedades del cliente HTTP subyacente, se puede personalizar el HttpClient utilizado por RestClient:
@Bean
public RestClient restClient() {
HttpClient httpClient = HttpClient.create()
.responseTimeout(Duration.ofSeconds(5));
ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
return RestClient.builder()
.connector(connector)
.build();
}
En esta configuración, se establece un timeout de 5 segundos para las respuestas, lo que es importante para mantener la resiliencia de la aplicación ante servicios externos lentos o no disponibles.
El RestClient también soporta la adición de interceptores o filters para modificar peticiones y respuestas de forma centralizada:
@Bean
public RestClient restClient() {
ExchangeFilterFunction logFilter = ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
System.out.println("Realizando petición a " + clientRequest.url());
return Mono.just(clientRequest);
});
return RestClient.builder()
.filter(logFilter)
.build();
}
Este filter de ejemplo permite registrar en el log cada petición realizada, mejorando la observabilidad de las interacciones con APIs externas.
El manejo de errores en RestClient se puede realizar utilizando el método onStatus()
para comprobar códigos de estado y lanzar excepciones personalizadas:
public Usuario obtenerUsuario(Long id) {
return restClient.get()
.uri("/usuarios/{id}", id)
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response -> {
return Mono.error(new ClienteException("Error del cliente"));
})
.onStatus(HttpStatus::is5xxServerError, response -> {
return Mono.error(new ServidorException("Error del servidor"));
})
.body(Usuario.class);
}
Con este enfoque, se puede proporcionar un manejo específico para diferentes tipos de errores HTTP, mejorando la robustez de la aplicación.
Para casos en los que se necesite enviar solicitudes con tipos de contenido específicos, como JSON o XML, el RestClient utiliza los encoders y decoders configurados en el contexto de Spring Web. Si se requiere personalización, se pueden especificar encoders adicionales:
@Bean
public RestClient restClient() {
return RestClient.builder()
.exchangeStrategies(ExchangeStrategies.builder()
.codecs(configurer -> configurer
.defaultCodecs()
.jackson2JsonEncoder(new Jackson2JsonEncoder(new ObjectMapper(), MediaType.APPLICATION_JSON)))
.build())
.build();
}
Esta configuración permite ajustar cómo se serializan y deserializan los objetos en las peticiones y respuestas, asegurando la compatibilidad con los servicios externos.
En términos de asincronía, aunque RestClient está diseñado principalmente para operaciones síncronas, puede integrarse con APIs reactivas cuando se utiliza en combinación con WebClient, permitiendo un manejo más eficiente de los recursos en aplicaciones de alta concurrencia.
Es importante destacar que, al utilizar RestClient, se adopta una forma de construir peticiones más alineada con las prácticas modernas de Java, utilizando un estilo fluido y enfocado en la inmutabilidad y la composición de funciones.
Ejercicios de esta lección Clientes RestTemplate y RestClient
Evalúa tus conocimientos de esta lección Clientes RestTemplate y RestClient con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
API Query By Example (QBE)
Identificadores y relaciones JPA
Borrar datos de base de datos
Web y Test Starters
Métodos find en repositorios
Controladores Spring MVC
Inserción de datos
CRUD Customers Spring MVC + Spring Data JPA
Backend API REST con Spring Boot
Controladores Spring REST
Uso de Spring con Thymeleaf
API Specification
Registro de usuarios
Crear entidades JPA
Asociaciones en JPA
Asociaciones de entidades JPA
Integración con Vue
Consultas JPQL
Open API y cómo agregarlo en Spring Boot
Uso de Controladores REST
Repositorios reactivos
Inyección de dependencias
Introducción a Spring Boot
CRUD y JPA Repository
Inyección de dependencias
Vista en Spring MVC con Thymeleaf
Servicios en Spring
Operadores Reactivos
Configuración de Vue
Entidades JPA
Integración con Angular
API Specification
API Query By Example (QBE)
Controladores MVC
Anotaciones y mapeo en JPA
Consultas JPQL con @Query en Spring Data JPA
Repositorios Spring Data
Inyección de dependencias
Data JPA y Mail Starters
Configuración de Angular
Controladores Spring REST
Configuración de Controladores MVC
Consultas JPQL con @Query en Spring Data JPA
Actualizar datos de base de datos
Verificar token JWT en peticiones
Login de usuarios
Integración con React
Configuración de React
Todas las lecciones de SpringBoot
Accede a todas las lecciones de SpringBoot y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Spring Boot
Introducción Y Entorno
Spring Boot Starters
Introducción Y Entorno
Inyección De Dependencias
Introducción Y Entorno
Controladores Spring Mvc
Spring Web
Vista En Spring Mvc Con Thymeleaf
Spring Web
Controladores Spring Rest
Spring Web
Open Api Y Cómo Agregarlo En Spring Boot
Spring Web
Servicios En Spring
Spring Web
Clientes Resttemplate Y Restclient
Spring Web
Rxjava En Spring Web
Spring Web
Crear Entidades Jpa
Persistencia Spring Data
Asociaciones De Entidades Jpa
Persistencia Spring Data
Repositorios Spring Data
Persistencia Spring Data
Métodos Find En Repositorios
Persistencia Spring Data
Inserción De Datos
Persistencia Spring Data
Actualizar Datos De Base De Datos
Persistencia Spring Data
Borrar Datos De Base De Datos
Persistencia Spring Data
Consultas Jpql Con @Query En Spring Data Jpa
Persistencia Spring Data
Api Query By Example (Qbe)
Persistencia Spring Data
Api Specification
Persistencia Spring Data
Repositorios Reactivos
Persistencia Spring Data
Introducción E Instalación De Apache Kafka
Mensajería Asíncrona
Crear Proyecto Con Apache Kafka
Mensajería Asíncrona
Creación De Producers
Mensajería Asíncrona
Creación De Consumers
Mensajería Asíncrona
Kafka Streams En Spring Boot
Mensajería Asíncrona
Introducción A Spring Webflux
Reactividad Webflux
Spring Data R2dbc
Reactividad Webflux
Controlador Rest Reactivo Basado En Anotaciones
Reactividad Webflux
Controlador Rest Reactivo Funcional
Reactividad Webflux
Operadores Reactivos Básicos
Reactividad Webflux
Operadores Reactivos Avanzados
Reactividad Webflux
Cliente Reactivo Webclient
Reactividad Webflux
Introducción A Spring Security
Seguridad Con Spring Security
Seguridad Basada En Formulario En Mvc Con Thymeleaf
Seguridad Con Spring Security
Registro De Usuarios
Seguridad Con Spring Security
Login De Usuarios
Seguridad Con Spring Security
Verificar Token Jwt En Peticiones
Seguridad Con Spring Security
Seguridad Jwt En Api Rest Spring Web
Seguridad Con Spring Security
Seguridad Jwt En Api Rest Reactiva Spring Webflux
Seguridad Con Spring Security
Autenticación Y Autorización Con Anotaciones
Seguridad Con Spring Security
Testing Unitario De Componentes Y Servicios
Testing Con Spring Test
Testing De Repositorios Spring Data Jpa
Testing Con Spring Test
Testing Controladores Spring Mvc Con Thymeleaf
Testing Con Spring Test
Testing Controladores Rest Con Json
Testing Con Spring Test
Testing De Aplicaciones Reactivas Webflux
Testing Con Spring Test
Testing De Seguridad Spring Security
Testing Con Spring Test
Testing Con Apache Kafka
Testing Con Spring Test
Integración Con Angular
Integración Frontend
Integración Con React
Integración Frontend
Integración Con Vue
Integración Frontend
En esta lección
Objetivos de aprendizaje de esta lección
- Aprender a usar RestTemplate
- Aprender a usar RestClient
- Entender las diferencias entre RestTemplate y RestClient