Consumo de API REST con Spring Boot
Si definiste una arquitectura basada en microservicios es muy probable que en alguna parte establezcas la comunicación entre dos servicios a través del intercambio de datos o el consumo de los mismos, en este artículo te explico de forma sencilla como consumir desde un servicio los datos brindados por otro servicio Rest.
En este ejemplo se diseña un microservicio que brinda datos de Películas, retornando una lista de películas generadas a partir de la siguiente clase modelo:
package microservice.Model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Movie { @Id @GeneratedValue private int id; private String name; private String description; public Movie() {} public Movie(int id, String name, String description) { super(); this.id = id; this.name = name; this.description = description; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
Se define además un Repositorio para acceder a las funciones que brinda JPA y persistir y acceder a los datos de las películas:
package microservice.Repository; import org.springframework.data.jpa.repository.JpaRepository; import microservice.Model.Movie; public interface MovieRepository extends JpaRepository<Movie, Integer> { }
La Clase Controladora que brinda los endpoints a consumir es la siguiente:
package microservice.Controllers; import java.util.List; import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import microservice.Model.Movie; import microservice.Repository.MovieRepository; @RestController @RequestMapping("/api/movies") public class MovieController { @Autowired MovieRepository movieRepository; @RequestMapping("/") public List<Movie> getAllMovies(){ List<Movie> movies = movieRepository.findAll(); return movies; } }
Ahora pasemos al microservicio que consume los datos de las películas, específicamente a la clase controladora donde se ejecuta el método que consume el servicio:
package microservice.Services; import java.util.Arrays; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import microservice.Models.Movie; @Service public class MoviesService { @Autowired RestTemplate restTemplate; public List<Movie> getMovies(){ ResponseEntity<Movie[]> response = restTemplate.getForEntity( "http://services-movies/api/movies/", Movie[].class); Movie[] movies = response.getBody(); List<Movie> m = Arrays.asList(movies); return m; } }
Como pueden notar en varias ocaciones se referencia la clase Movie, por lo que debemos crear este modelo para poder referenciarlo:
package microservice.Models; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Movie { @Id @GeneratedValue private int id; private String name; private String description; public Movie() {} public Movie(int id, String name, String description) { super(); this.id = id; this.name = name; this.description = description; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
Para consumir los servicios se propone el uso de RestTemplate, en este caso se inyecta un Bean en la clase Controladora.
@Autowired RestTemplate restTemplate;
Para esto debemos crear el bean en algún lugar en el path del proyecto, recomiendo hacerlo en la clase Main:
package microservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class Main { @Bean public RestTemplate getresttemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(Main.class, args); } }
Retomando el método que consume los datos tenemos dos posibles soluciones :
uso de getForEntity:
public List<ResponseEntity<Movie[]>> getMovies(){ ResponseEntity<Movie[]> mov = restTemplate.getForEntity( "http://services-movies/api/movies/", Movie[].class); List<ResponseEntity<Movie[]>> m = Arrays.asList(mov); return m; }
uso de getForObject :
public List<Movie> getMovies(){ Movie[] me = restTemplate.getForObject( "http://services-movies/api/movies/", Movie[].class); List<Movie> m = Arrays.asList(me); return m; }
Te invito a probarlas y ver cual es la principal diferencia en los resultados devueltos por cada una.
Seguro notaron que se utiliza “services-movies” en la url del servicio, esto es así porque todo el ejemplo en github está contado bajo el patrón service discovery que será explicado en otro artículo.
De esta forma ya tenemos los datos brindados por el primer servicio almacenados en la variable m. Puede acceder al código completo en este enlace.
Espero que este artículo les haya sido útil, nos leemos en el próximo!!!!!