fbpx

@HttpExchange en SPRING BOOT 3

Desde Spring Boot 3 tenemos la posibilidad de realizar peticiones HTTP de forma declarativa con el propio framework gracias al uso de la anotación @HttpExchange, antiguamente hemos podido usar FeignClient para hacer peticiones HTTP en forma de declarativa.

Vídeo explicativo

¿Qué es una interfaz Http declarativa?

Una interfaz HTTP declarativa es una interfaz Java que ayuda a reducir el código repetitivo, genera un proxy que implementa esta interfaz y realiza los intercambios a nivel de framework.

Por ejemplo, si queremos consumir una API en la URL https://servidor.com/api/usuarios/id, tenemos que crear y configurar un bean RestTemplate o WebClient y utilizar sus métodos de intercambio para invocar la API, analizar la respuesta y gestionar los errores.

La mayoría de las veces, el código para crear y configurar los beans e invocar APIs remotas es muy similar y por lo tanto puede ser abstraído por el framework, por lo que no necesitamos escribir este código una y otra vez en cada aplicación. Podemos simplemente expresar los detalles de la API remota utilizando las anotaciones en una interfaz y dejar que el framework cree una implementación bajo el capó.

Por ejemplo, si queremos consumir una API HTTP GET /users entonces podemos simplemente escribir:

public interface UserClient {
  @GetExchange("/users")
  Flux<User> getAll();
}

Spring proporcionará la interfaz y las implementaciones de intercambio en tiempo de ejecución, y sólo tendremos que invocar el método getAll().

@Autowired
UserClient userClient;
userClient.getAll().subscribe(
    data -> log.info("User: {}", data)
);

Maven o Gradle dependencias

Para utilizar las interfaces Http declarativas necesitas 2 dependencias de Spring Boot 3 spring-boot-starter-web or spring-boot-starter-webflux:

Maven

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Gradle

implementation 'org.springframework.boot:spring-boot-starter-web:3.0.6'
implementation 'org.springframework.boot:spring-boot-starter-webflux:3.0.6'

Creando de una interfaz de servicio HTTP

En Spring, una interfaz de servicio HTTP es una interfaz Java con métodos @HttpExchange. El método anotado se trata como un punto final HTTP, y los detalles se definen estáticamente a través de atributos de anotación, así como a través de los tipos de argumentos del método de entrada.

Métodos Exchange

Podemos utilizar las siguientes anotaciones para marcar un método como endpoint de servicio HTTP:

  • @HttpExchange: es la anotación genérica para especificar un endpoint HTTP. Cuando se utiliza a nivel de interfaz, se aplica a todos los métodos.
  • @GetExchange: especifica @HttpExchange para peticiones HTTP GET.
  • @PostExchange: especifica @HttpExchange para peticiones HTTP POST.
  • @PutExchange: especifica @HttpExchange para peticiones HTTP PUT.
  • @DeleteExchange: especifica @HttpExchange para solicitudes HTTP DELETE.
  • @PatchExchange: especifica @HttpExchange para peticiones HTTP PATCH.

Argumentos

Los métodos de intercambio admiten los siguientes parámetros en la firma del método:

  • @PathVariable: sustituye un valor por un marcador de posición en la URL de la solicitud.
  • @RequestBody: proporciona el cuerpo de la solicitud.
  • @RequestParam: añade los parámetros de la petición. Cuando “content-type” está configurado como “application/x-www-form-urlencoded”, los parámetros de la petición se codifican en el cuerpo de la petición. En caso contrario, se añaden como parámetros de consulta de la URL.
  • @RequestHeader: añade los nombres y valores de las cabeceras de la petición.
  • @RequestPart: se puede utilizar para añadir una parte de la petición (campo de formulario, recurso o HttpEntity etc).
  • @CookieValue: añade cookies a la petición.

Valores de retorno

Un método de intercambio HTTP puede devolver valores que son:

  • Clases o clases reactivas (Mono/Flux).
  • Sólo la información de respuesta específica, como el código de estado y/o las cabeceras de respuesta.
  • void si el método se trata como sólo de ejecución.

Creando un HttpServiceProxyFactory

HttpServiceProxyFactory es una fábrica para crear un proxy de cliente a partir de una interfaz de servicio HTTP. Utiliza su método HttpServiceProxyFactory.builder(client).build() para obtener una instancia del bean proxy.

@Configuration
public class WebConfig {
  @Bean
  WebClient webClient(ObjectMapper objectMapper) {
    return WebClient.builder()
        .baseUrl("https://jsonplaceholder.typicode.com/")
        .build();
  }
  @SneakyThrows
  @Bean
  UserClient postClient(WebClient webClient) {
    HttpServiceProxyFactory httpServiceProxyFactory =
        HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient))
            .build();
    return httpServiceProxyFactory.createClient(UserClient.class);
  }
}

Ejemplo de una interfaz HTTP

A continuación se muestra un ejemplo de interfaz HTTP que interactúa con el endpoint https://jsonplaceholder.typicode.com/users/ y realiza diversas operaciones.

@HttpExchange(url = "/users", accept = "application/json", contentType = "application/json")
public interface UserClient {
  @GetExchange("/")
  List<User> getAll();
  @GetExchange("/{id}")
  User getById(@PathVariable("id") Long id);
  @PostExchange("/")
  ResponseEntity<Void> save(@RequestBody User user);
  @PutExchange("/{id}")
  ResponseEntity<Void> update(@PathVariable Long id, @RequestBody User user);
  @DeleteExchange("/{id}")
  Mono<ResponseEntity<Void>> delete(@PathVariable Long id);
}