feign deklaratywny klient http

Feign deklaratywny klient http

Współczesne aplikacje coraz częściej komunikują się ze sobą, coraz częściej korzystają także z różnego rodzaju api udostępnianego publicznie przez różnych dostawców. Najprostszą i chyba najczęściej wykorzystywaną metodą łączenia się z różnymi serwisami poprzez takie api, jest użyciu klienta http. Implementacji różnych klientów jest wiele. Ja dzisiaj opiszę Feigna, klienta deklaratywnego, który pozwala nam zmniejszyć ilość pisanego kodu oraz znacznie ułatwić pracę.

 

Czym jest Feign?

Feign jest deklaratywnym klientem http, co oznacza, że deklarujemy, co nasz klient ma robić, zamiast pisać, jak ma coś robić (tak jak to jest w przypadku innych klientów http). Jeśli używamy Spring Boota, to wystarczy jedna adnotacja do uruchomienia autokonfiguracji Feigna (@EnableFeignClients). Spring utworzy za nas takiego klienta i będziemy mogli go wstrzykiwać, tak jak wstrzykujemy inne beany.

Przykładowa deklaracja klienta Feign:

@FeignClient(url = "http://example.com") //1
public interface ProductClient {
    @RequestMapping(method = RequestMethod.GET, value = "/products") //2
    List<Product> getProducts(@Param long companyId); //3
}
  1. Deklaracja klienta za pomocą adnotacji @FeignClient. Jako parametr podajemy url serwisu, do którego chcemy się połączyć.
  2. Deklaracja metody, która będzie łączyła się z odpowiednim zasobem.
  3. Metoda, którą będziemy posługiwali się w naszym kodzie.

 

Użycie takiego klienta jest bardzo proste i sprowadza się do wstrzyknięcia beana klienta oraz wywołania odpowiedniej metody:

@RestController
class ProductController {

  private final ProductClient productClient;

  public ProductController(ProductClient productClient) {
    this.productClient = productClient;
  }

  @GetMapping("/products/{companyId}")
  public List<Product> getProducts(@PathVariable long companyId) {
    return productClient.getProducts(companyId);
  }
}

Poza zadeklarowaniem interfejsu i oznaczeniu go odpowiednimi adnotacjami nie napisałem, żadnego kodu związanego z wykonaniem danego zapytania. Prawda, że proste?

 

Inne klienty http

Apche commons HttpClient / Http Components

Gdy pierwszy raz używałem HttpClient, wydał mi się całkiem prosty. Wtedy dopiero zaczynałem moją przygodę z Javą i umiałem już używać oraz tworzyć klienty http w php poprzez np. fsockopen, więc robienie tego samego w Javie było dosyć proste.

Po krótkim czasie przesiadłem się na kolejną wersję HttpClient’a, który wraz z wersją 4 zmienił nazwę na Apache HttpComponents. Poza nazwą zmieniło się też api, które nawet teraz po wielu latach nie wydaje mi się zbyt przyjazne. HttpComponents daje za to bardzo duże możliwości. Można m.in. skonfigurować pulę wątków tak, by klient wykonywał zapytania równolegle w wielu wątkach. Może to być przydatne jeśli potrzebujesz napisać robota, który przemierza strony w poszukiwaniu różnych interesujących Cię treści. Nie trzeba oprogramowywać wielowątkowości samodzielnie, klient zrobi to za nas.

Jedną z pierwszych rzeczy jakie robiłem z klientami http, było właśnie pisanie takich robotów. Oba te klienty mają jednak podobną wadę, konfiguracja ich bywa czasem kłopotliwa ze względu na mnogość opcji, które nam dają oraz mało intuicyjne api.

 

RestTemplate

Kolejnym podobnym klientem jest springowy RestTemplate, jest on chyba najprostszy z tych wszystkich trzech. Jego wadą jest to (moim zdaniem), że api, które udostępnia i to jak się z nimi pracuje jest czasem mało wygodne. Nie wymaga natomiast dużo konfiguracji, a także potrafi skonwertować jsona na obiekty, co jest bardzo przydatne. Kolejną zaletą jest to, że istnieje także implementacja przeznaczona dla microserwisów z wbudowanym load balancerem i integracją z service discovery (wstrzykiwana adnotacją @LoadBalanced, którą znajdziemy w  Spring Cloud).

Poza wyżej wymienionymi jest jeszcze Jersey, do którego miałem kilka podejść, ale jego api zupełnie mi nie odpowiada, więc postanowiłem więcej do niego nie wracać.

Proste rozwiązania są najlepsze

Kiedy potrzebowałem wygodnego klienta, zwykle robiłem własną implementację z fluent api, która przykrywała HttpComponents lub RestTemplate. Było to bardzo wygodne rozwiązanie i używało się go bardzo intuicyjnie, ale nadal było to rozwiązanie imperatywne, które z każdym użyciem generowało co najmniej kilka linijek kodu. Przy dużej ilości wywołań różnych endpointów http może stać się to dosyć uciążliwe.

Dlatego w projektach, w których nie mam zbyt dużo takich wywołań, używam RestTemplate, głównie ze względu na jego prostotę, ale także dlatego, że jest zawsze pod ręką. W większości projektów używam Springa, więc RestTemplate jest tutaj naturalnym wyborem.

 

Jak to jest zrobione ?

Tak naprawdę Feign nie jest klientem http, tylko bardziej biblioteką, która używa klientów http takich jak Apache HttpComponents czy OkHttp. Generuje kod dla tych klientów i pozwala nam ich używać w bardzo wygodny sposób. Dzięki czemu cała logika związana z zapytaniami jest przed nami ukryta i nie miesza się z naszym kodem biznesowym.

 

Feign w microserwisach

Feign został stworzony przez Netflixa i od początku przeznaczony był do pracy w środowisku microserwisów, potrafi więc korzystać z service discovery (może to być np. Eureka lub jakiś inny mechanizm discovery dostarczany np. przez chmurę. Feign używa Ribbona do łączenia się z discovery i rozkładania ruchu na poszczególne instancje aplikacji (jest to load balancing client side).

 

Feign

Instancje poszczególnych (micro) serwisów rejestrują się w serwis discovery, po czym Feign może pobrać listę zarejestrowanych serwisów. Zwykle serwisy rejestrują się pod jakąś nazwą (string) np. Service1, Service2.

W konfiguracji klienta (w adnotacji @FeignClient) zmieniamy jedynie parametr url na name.

@FeignClient((name = "Service2")

Oczywiście trzeba pamiętać o uruchomieniu autokonfiguracji klienta discovery w spring bootcie, poprzez @EnableDiscoveryClient i możemy cieszyć się działającym połączeniem pomiędzy naszymi microserwisami.

 

Dlaczego klient deklaratywny jest lepszy?

Po zdefiniowaniu odpowiedniego interfejsu jedyne co musimy zrobić, to wywołać w naszym kodzie metody, którą zdefiniowaliśmy wraz z wszystkimi parametrami:

productClient.getProducts(companyId);

Nic więcej nie zaśmieca kodu, nie musimy ręcznie tworzyć repozytorium, w którym będziemy trzymać implementację wywołań metod api, wystarczy tylko interfejs

Feign podobnie jak Spring Data minimalizuje szablonowy kod (boiler plate code), który trzeba pisać przy pobieraniu podobnie u strukturyzowanych danych. Im mniej kodu, tym lepiej 😉

 

Podsumowanie

Zawsze warto zmniejszać ilość kodu, pisanego ręcznie, poprawia to znacznie komfort pracy i przede wszystkim wprowadza większy porządek w projekcie. Podobne rozwiązanie zastosowano w frameworku Micronaut, o którym pisałem na blogu jakiś czas temu. Więcej znajdziesz w dokumentacji.

 

PS. Artykuł został przeniesiony z mojego starego bloga, którego już dawno nie rozwijam. W ten sposób chciałem ocalić go od zapomnienia 😉

 

Źródła:

Dokumentacja w projekcie spring
Strona projektu

 

Mateusz Dąbrowski

Cześć jestem Mateusz, zajmuję się programowaniem już ponad 12 lat z czego ponad 8 programuję w Javie. Zapraszam Cię do lektury mojego bloga. Możesz przeczytać więcej o mnie >>TUTAJ<<

4 thoughts to “Feign deklaratywny klient http”

  1. Dzięki. Potrzebowałem szybkiego artykułu by przekazać komuś początkującemu i ten jest chyba najlepszy w PL

Komentarze są zamknięte.