feign-reactive

repository·develop·Indexed 20 days ago

https://github.com/playtikaoss/feign-reactive

A reactive, non-blocking implementation of the Feign declarative HTTP client designed for Spring WebFlux, Project Reactor, and RxJava. It provides a concise syntax for client-side APIs on top of Spring WebClient, Java 11 HttpClient, and Jetty. The library includes modules for Spring Cloud integration (Ribbon, Hystrix, CircuitBreaker, and LoadBalancer) and supports auto-configuration via @EnableReactiveFeignClients in Spring Boot.

Tokens
5K
Snippets
10
Records
20
Agent score
65%

What's inside feign-reactive

  1. Available feign-reactive modules

    develop

    The project is divided into several modules depending on your runtime and reactive library requirements:

    • feign-reactor-core: Base classes and interfaces for implementing alternative reactor Feign implementations.
    • feign-reactor-webclient: Implementation based on Spring WebClient.
    • feign-reactor-cloud: Spring Cloud implementation (supports Ribbon/Hystrix).
    • feign-reactor-java11: Implementation based on Java 11 HttpClient (high performance).
    • feign-reactor-rx2: Rx2 compatible implementation (depends on feign-reactor-webclient).
    • feign-reactor-rx3: Rx3 compatible implementation (depends on feign-reactor-webclient).
    • feign-reactor-jetty: Experimental Reactive Jetty client implementation. Offers higher reactivity by streaming request bodies and receiving responses before the request body is fully sent.
    • feign-reactor-spring-cloud-starter: Single dependency for Spring Cloud applications (uses WebClient by default).
    • feign-reactor-bom: Maven BOM for simplified dependency management.
  2. How to use feign-reactive with RxJava2 or RxJava3

    develop

    For RxJava users, define your Feign API interface where every method:

    • May accept Flowable, Observable, Single, or Maybe as a request body.
    • Must return Flowable, Observable, Single, or Maybe.

    Use Rx2ReactiveFeign or Rx3ReactiveFeign to build the client.

    @Headers({"Accept: application/json"})
    public interface IcecreamServiceApi {
    
      @RequestLine("GET /icecream/flavors")
      Flowable<Flavor> getAvailableFlavors();
    
      @RequestLine("POST /icecream/orders")
      @Headers("Content-Type: application/json")
      Single<Bill> makeOrder(IceCreamOrder order);
    
      @RequestLine("POST /icecream/bills/pay")
      @Headers("Content-Type: application/json")
      Single<Long> payBill(Bill bill);
    }
    
    // Build the client
    IcecreamServiceApi client = Rx2ReactiveFeign
        .builder()
        .target(IcecreamServiceApi.class, "http://www.icecreame.com");
    
    // Execute nonblocking requests
    Flowable<Flavor> flavors = client.getAvailableFlavors();
  3. How to use feign-reactive with Project Reactor

    develop

    To use the Reactor-based implementation, define your Feign API interface where every method:

    • May accept org.reactivestreams.Publisher as a request body.
    • Must return reactor.core.publisher.Mono or reactor.core.publisher.Flux.

    Use WebReactiveFeign (for WebClient), JettyReactiveFeign, or Java11ReactiveFeign to build the client.

    @Headers({ "Accept: application/json" })
    public interface IcecreamServiceApi {
    
      @RequestLine("GET /icecream/flavors")
      Flux<Flavor> getAvailableFlavors();
    
      @RequestLine("POST /icecream/orders")
      @Headers("Content-Type: application/json")
      Mono<Bill> makeOrder(IceCreamOrder order);
    
      @RequestLine("POST /icecream/bills/pay")
      @Headers("Content-Type: application/json")
      Mono<Void> payBill(Publisher<Bill> bill);
    }
    
    // Build the client
    IcecreamServiceApi client = WebReactiveFeign
                .<IcecreamServiceApi>builder()
                .target(IcecreamServiceApi.class, "http://www.icecreame.com");
    
    // Execute nonblocking requests
    Flux<Flavor> flavors = client.getAvailableFlavors();
  4. Use Cloud2 (CircuitBreaker + LoadBalancer)

    develop

    For Spring Cloud 2.2.0+ environments, it is highly recommended to use the cloud2 module (CircuitBreaker + LoadBalancer) instead of the legacy cloud module.

    Setup: Add the feign-reactor-cloud module to your classpath and exclude the legacy feign-reactor-cloud (if applicable/necessary for your dependency tree).

    Global Toggle Properties:

    • reactive.feign.loadbalancer.enabled: Disable loadbalancer configuration.
    • reactive.feign.circuit.breaker.enabled: Disable circuit breaker configuration.

    Configuration via Beans:

    • LoadBalancer: Define a ReactiveLoadBalancer.Factory bean in your client configuration.
    • CircuitBreaker: Use a ReactiveFeignCircuitBreakerFactory bean, or a ReactiveCircuitBreakerFactory combined with a ReactiveFeignCircuitBreakerCustomizer bean.

    New Retry Properties (Cloud2): Unlike the legacy module, LoadBalancer in Cloud2 does not have a direct retry configuration, but you can use:

    • retryOnSame: Number of retries for the same server.
    • retryOnNext: Number of retries for the next server.
  5. Enable Reactive Feign Clients in Spring Boot

    develop

    To enable auto-configuration for reactive Feign clients, add the @EnableReactiveFeignClients annotation to your Spring Boot configuration class. This will cause all interfaces annotated with @ReactiveFeignClient to be instantiated and configured as Spring beans.

    When defining a client:

    • Use the name attribute in @ReactiveFeignClient. By default, the bean is registered as name + "ReactiveFeignClient" unless a qualifier is specified.
    • Cloud Mode: The name attribute is used as the Eureka application name.
    • Cloudless Mode: You must specify the url attribute.
    @Configuration
    @EnableReactiveFeignClients
    public class MyFeignConfig {
        // Clients annotated with @ReactiveFeignClient will now be beans
    }
    
    @ReactiveFeignClient(name = "my-service")
    public interface MyServiceClient {
        // ...
    }
  6. Add headers to reactive requests

    develop

    You have two primary ways to add headers to your requests:

    1. ReactiveHttpRequestInterceptor: Use this for dynamic headers, such as extracting an authentication token from the Reactor subscriberContext.
    2. @RequestHeader parameter: Use the standard Feign @RequestHeader annotation on specific method parameters to pass a single header or a map of headers.
    // Using an interceptor to add a static header and a dynamic header from context
    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)));
  7. Use Cloud Mode (Hystrix + Ribbon)

    develop

    To use the legacy Cloud mode (Hystrix + Ribbon), add the feign-reactor-cloud module to your classpath.

    Global Toggle Properties (useful for testing):

    • reactive.feign.cloud.enabled: Disable cloud configuration for all clients.
    • reactive.feign.ribbon.enabled: Disable loadbalancer configuration.
    • reactive.feign.hystrix.enabled: Disable Hystrix configuration.
    • reactive.feign.logger.enabled: Enable default logger.
    • reactive.feign.metrics.enabled: Enable default Micrometer logger (requires a Micrometer implementation in your dependencies).

    Specific Bean Customization:

    • Ribbon: Define a ReactiveLoadBalancer.Factory or ReactiveRetryPolicies bean in your configuration.
    • Hystrix: Define a CloudReactiveFeign.SetterFactory bean in your configuration.
  8. Configure Reactive Feign via application.properties

    develop

    You can configure specific settings for Feign clients using the prefix reactive.feign.client.config.<client-name>.

    Available properties include:

    • options: Reactive HTTP client specific options (refer to ReactiveOptions.Builder for implementation details).
    • retry: Retry configuration (see ReactiveFeignClientProperties.RetryConfiguration).
    • statusHandler: Class implementing ReactiveStatusHandler (replaces regular Feign ErrorDecoder).
    • errorMapper: Class implementing ReactiveErrorMapper.
    • requestInterceptors: Classes of ReactiveHttpRequestInterceptor for setting up request headers.
    • logger: Class of ReactiveLoggerListener.
    • metricsLogger: Class of MicrometerReactiveLogger.
    • decode404: Boolean to handle 404 decoding (matches regular Feign behavior).
  9. Configure Reactive Feign via Configuration Classes

    develop

    You can provide configuration via Java classes using two levels of scope:

    1. Global Default: Use the defaultConfiguration attribute on @EnableReactiveFeignClients to specify a class used for all clients.
    2. Client Specific: Use the configuration attribute on @ReactiveFeignClient to specify a class for a single client.

    The following bean types can be defined in your configuration classes:

    • ReactiveOptions.Builder
    • ReactiveRetryPolicies
    • List<Class<ReactiveHttpRequestInterceptor>>
    • ReactiveStatusHandler
    • feign.codec.ErrorDecoder
    • ReactiveErrorMapper
    • ReactiveLoggerListener
    • MicrometerReactiveLogger