Skip to content

Latest commit

 

History

History
182 lines (131 loc) · 7.53 KB

README.md

File metadata and controls

182 lines (131 loc) · 7.53 KB

CircleCI codecov Codacy Badge Maven Central

feign-reactive

Use Feign with Spring WebFlux

This fork was created in order to provide support for Spring Boot 3.2 since there is an unresolved issue in the original project. Credit for the fix belongs to ramzes3333. I just relased a new version with his fix and published it to Maven Central.

Overview

Implementation of Feign on Spring WebClient. Brings you the best of two worlds together : concise syntax of Feign to write client side API on fast, asynchronous and non-blocking HTTP client of Spring WebClient.

Modules

feign-reactor-core : base classes and interfaces that should allow to implement alternative reactor Feign

feign-reactor-webclient : Spring WebClient based implementation of reactor Feign

feign-reactor-cloud : Spring Cloud implementation of reactor Feign (Ribbon/Hystrix)

feign-reactor-java11 : Java 11 HttpClient based implementation of reactor Feign (!! Winner of benchmarks !!)

feign-reactor-rx2 : Rx2 compatible implementation of reactor Feign (depends on feign-reactor-webclient)

feign-reactor-jetty : experimental Reactive Jetty client based implementation of reactor Feign (doesn't depend on feign-reactor-webclient). In future will allow to write pure Rx2 version.

  • have greater reactivity level then Spring WebClient. By default don't collect body to list instead starts sending request body as stream.
  • starts receiving reactive response before all reactive request body has been sent
  • process Flux<String> correctly in request and response body

feign-reactor-spring-cloud-starter : Single dependency to have reactive feign client operabable in your spring cloud application. Uses webclient as default client implementation.

feign-reactor-bom : Maven BOM module which simplifies dependency management for all reactive feign client modules.

Usage

Write Feign API as usual, but every method of interface

  • may accept org.reactivestreams.Publisher as body
  • must return reactor.core.publisher.Mono or reactor.core.publisher.Flux.
@Headers({ "Accept: application/json" })
public interface IcecreamServiceApi {

  @RequestLine("GET /icecream/flavors")
  Flux<Flavor> getAvailableFlavors();

  @RequestLine("GET /icecream/mixins")
  Flux<Mixin> getAvailableMixins();

  @RequestLine("POST /icecream/orders")
  @Headers("Content-Type: application/json")
  Mono<Bill> makeOrder(IceCreamOrder order);

  @RequestLine("GET /icecream/orders/{orderId}")
  Mono<IceCreamOrder> findOrder(@Param("orderId") int orderId);

  @RequestLine("POST /icecream/bills/pay")
  @Headers("Content-Type: application/json")
  Mono<Void> payBill(Publisher<Bill> bill);
}

Build the client :

/* Create instance of your API */
IcecreamServiceApi client = 
             WebReactiveFeign  //WebClient based reactive feign  
             //JettyReactiveFeign //Jetty http client based
             //Java11ReactiveFeign //Java 11 http client based
            .<IcecreamServiceApi>builder()
            .target(IcecreamServiceApi.class, "http://www.icecreame.com")

/* Execute nonblocking requests */
Flux<Flavor> flavors = icecreamApi.getAvailableFlavors();
Flux<Mixin> mixins = icecreamApi.getAvailableMixins();

or cloud aware client :

 IcecreamServiceApi client = CloudReactiveFeign.<IcecreamServiceApi>builder(WebReactiveFeign.builder())
            .setLoadBalancerCommandFactory(s -> LoadBalancerCommand.builder()
                    .withLoadBalancer(AbstractLoadBalancer.class.cast(getNamedLoadBalancer(serviceName)))
                    .withRetryHandler(new DefaultLoadBalancerRetryHandler(1, 1, true))
                    .build())
            .fallback(() -> Mono.just(new IcecreamServiceApi() {
                @Override
                public Mono<String> get() {
                    return Mono.just("fallback");
                }
            }))
            .target(IcecreamServiceApi.class,  "http://" + serviceName);

/* Execute nonblocking requests */
Flux<Flavor> flavors = icecreamApi.getAvailableFlavors();
Flux<Mixin> mixins = icecreamApi.getAvailableMixins();

Rx2 Usage

Write Feign API as usual, but every method of interface

  • may accept Flowable, Observable, Single or Maybe as body
  • must return Flowable, Observable, Single or Maybe.
@Headers({"Accept: application/json"})
public interface IcecreamServiceApi {

  @RequestLine("GET /icecream/flavors")
  Flowable<Flavor> getAvailableFlavors();

  @RequestLine("GET /icecream/mixins")
  Observable<Mixin> getAvailableMixins();

  @RequestLine("POST /icecream/orders")
  @Headers("Content-Type: application/json")
  Single<Bill> makeOrder(IceCreamOrder order);

  @RequestLine("GET /icecream/orders/{orderId}")
  Maybe<IceCreamOrder> findOrder(@Param("orderId") int orderId);

  @RequestLine("POST /icecream/bills/pay")
  @Headers("Content-Type: application/json")
  Single<Long> payBill(Bill bill);

Build the client :

/* Create instance of your API */
IcecreamServiceApi client = Rx2ReactiveFeign
    .builder()
    .target(IcecreamServiceApi.class, "http://www.icecreame.com")

/* Execute nonblocking requests */
Flowable<Flavor> flavors = icecreamApi.getAvailableFlavors();
Observable<Mixin> mixins = icecreamApi.getAvailableMixins();

Header to request

There are 2 options:

ReactiveHttpRequestInterceptor

ReactiveFeignBuilder
    .addRequestInterceptor(ReactiveHttpRequestInterceptors.addHeader("Cache-Control", "no-cache"))
    .addRequestInterceptor(request -> Mono
            .subscriberContext()
            .map(ctx -> ctx
                    .<String>getOrEmpty("authToken")
                    .map(authToken -> {
                      MultiValueMapUtils.addOrdered(request.headers(), "Authorization", authToken);
                      return request;
                    })
                    .orElse(request)));

@RequestHeader parameter

You can use @RequestHeader annotation for specific parameter to pass one header or map of headers @RequestHeader example

Spring Auto-Configuration

You can enable auto-configuration of reactive Feign clients as Spring beans just by adding feign-reactor-spring-configuration module to classpath. Spring Auto-Configuration module Sample cloud auto-configuration project with Eureka/WebFlux/ReaciveFeign

License

Library distributed under Apache License Version 2.0.