Tworzenie własnej libki na potrzeby architektury mikroserwisowej to nie jest najlepszy pomysł. Z wielu powodów. Tym razem spójrz jak to zrobić, w sytuacji, kiedy jednak taką libke bardzo chcesz stworzyć.
Weźmy na warsztat taką sytuację:
“Komunikacja REST wymaga dodania nagłówków X, Y i Z.”
Masz wiele mikroserwisów i wszędzie te nagłówki muszą być wysyłane.
No to teraz, na przykładzie WebClienta, przejdźmy od najgorszego do najlepszego rozwiązania
Skonfigurowany WebClient
Twoja libka dostarcza gotowego WebClienta. Wystarczy, iż go użyjesz u siebie, aby wykonać zapytanie REST, wszystkie nagłówki są magicznie dołączone.
@Configuration public class WebClientConfig { @Bean WebClient webClient() { return WebClient.builder() .defaultHeader("x-header-x", "some-value-x") .defaultHeader("x-header-y", "some-value-y") .defaultHeader("x-header-z", "some-value-z") .build(); } }Po podniesieniu takie klasy konfiguracyjnej będziesz mieć gotowego do użycia WebClienta. Niby super. Ale…
Nie masz możliwości dodania kolejnych nagłówków.
Nie masz możliwości dodania filtrów.
Nie masz możliwości wpłynięcia na konfigurację serializacji (Jackson).
Twoja aplikacja musi być w pełni zgodna z założeniami libki, co do tego jak “pobrać” wartości dla nagłówków.
Generalnie nic nie możesz, jak chcesz coś zmienić, musisz zrobić wszystko manualnie od nowa.
Skonfigurowany WebClient.Builder
Trochę bardziej elastycznym rozwiązaniem, będzie dostarczenie prekonfigurowanego WebClient.Buildera.
@Configuration public class WebClientConfig { @Bean WebClient.Builder webClientBuilder() { return WebClient.builder() .defaultHeader("x-header-x", "some-value-x") .defaultHeader("x-header-y", "some-value-y") .defaultHeader("x-header-z", "some-value-z"); } }Wykorzystując go, możesz stworzyć WebClienta, jednocześnie dodając swoje customizacje.
Możesz dodać kolejne nagłówki
Możesz dodać filtry
Możesz dowolnie konfigurować serializacje
przez cały czas Twoja aplikacja musi być w pełni zgodna z założeniami libki.
Automagiczny filtr
Jeżeli masz ochotę na jeszcze większą elastyczność, to warto pójść w stronę własnego filtra. Dzięki temu masz dodatkowo kontrolę na tym, kiedy te nagłówki zostaną nadane.
public class MyCustomHeadersFilter implements ExchangeFilterFunction { @Override public Mono<ClientResponse> filter( ClientRequest request, ExchangeFunction next) { var headers = request.headers(); headers.add("x-header-x", "some-value-x"); headers.add("x-header-y", "some-value-y"); headers.add("x-header-z", "some-value-z"); return next.exchange(request); } }Taki filtr manualnie dodajesz, w wybrane przez siebie miejsce podczas tworzenia WebClienta w swojej apce. Nikt nic Ci automatycznie nie konfiguruje.
Masz pełną kontrolę nad Twoim WebClientem
Ty decydujesz w którym momencie zostaną dodane nagłówki
przez cały czas Twoja aplikacja musi być zgodna z założeniami libki. Filtr musi skądś wartości nagłówków pobrać.
Filtr z Supplierem
Aby uwolnić się od ostatniego problemu, musisz po prostu zparametryzować filtr!
@RequiredArgsConstructor public class MyCustomHeadersFilter implements ExchangeFilterFunction { private final Supplier<HeaderValues> valuesSupplier; @Override public Mono<ClientResponse> filter( ClientRequest request, ExchangeFunction next) { var headers = request.headers(); var values = valuesSupplier.get(); headers.add("x-header-x", values.getX()); headers.add("x-header-y", values.getY()); headers.add("x-header-z", values.getZ()); return next.exchange(request); } }Teraz, dodając filtr do swojego WebClienta, musisz przekazać mu tez funkcję, dzięki której zostaną dostarczone odpowiednie wartości z Twojej aplikacji. Masz pełną kontrolę nad tym, co tam przekażesz, a wartość będzie za każdym razem pobierana od nowa, dla wszystkich requestu.
Możesz tam pobierać informacje z requestu, który przyszedł do Twojej aplikacji, z kontekstu Security, z konfiguracji czy choćby generować je losowo.
Masz pełną kontrolę. Biblioteka nic Ci nie narzuca!