Code Monkey home page Code Monkey logo

feign-reactive's Introduction

Happy to announce that from now Java Reactive Feign client is officially backed by Playtika. All development will be conducted in Playtika fork https://github.com/Playtika/feign-reactive

Subscribe to stay up to date 🙂

feign-reactive

Download

Use Feign with Spring WebFlux

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-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

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 = ReactiveFeign
    .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()
    .setFallback(new TestInterface() {
        @Override
        public Mono<String> get() {
            return Mono.just("fallback");
        }
    })
    .setLoadBalancerCommand(
         LoadBalancerCommand.builder()
                 .withLoadBalancer(AbstractLoadBalancer.class.cast(getNamedLoadBalancer(serviceName)))
                 .withRetryHandler(new DefaultLoadBalancerRetryHandler(1, 1, true))
                 .build()
    )
    .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();

Maven

<repositories>
    <repository>
        <id>bintray-kptfh-feign-reactive</id>
        <name>bintray</name>
        <url>https://dl.bintray.com/kptfh/feign-reactive</url>
    </repository>
</repositories>
...
<dependencies>
    ...
    
    <dependency>
        <groupId>io.github.reactivefeign</groupId>
        <artifactId>feign-reactor-cloud</artifactId>
        <version>1.0.0</version>
    </dependency>
    
    or if you don't need cloud specific functionality
    
    <dependency>
        <groupId>io.github.reactivefeign</groupId>
        <artifactId>feign-reactor-webclient</artifactId>
        <version>1.0.0</version>
    </dependency>
    
    or if you tend to use Rx2 interfaces
    
    <dependency>
            <groupId>io.github.reactivefeign</groupId>
            <artifactId>feign-reactor-rx2</artifactId>
            <version>1.0.0</version>
        </dependency>
    ...
</dependencies>

License

Library distributed under Apache License Version 2.0.

feign-reactive's People

Contributors

alekseibevzenko avatar kptfh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

feign-reactive's Issues

Programmatically configuring CloudReactiveFeign for using Ribbon as loadbalancer

I am not able to configure the line
.withLoadBalancer(AbstractLoadBalancer.class.cast(getNamedLoadBalancer(serviceName)))
to use ribbon DynamicServerlistLoadBalancer. Any help would be appriciated.

IcecreamServiceApi client = CloudReactiveFeign.builder()
.setFallback(new TestInterface() {
@OverRide
public Mono get() {
return Mono.just("fallback");
}
})
.setLoadBalancerCommand(
LoadBalancerCommand.builder()
.withLoadBalancer(AbstractLoadBalancer.class.cast(getNamedLoadBalancer(serviceName)))
.withRetryHandler(new DefaultLoadBalancerRetryHandler(1, 1, true))
.build()
)
.target(IcecreamServiceApi.class, "http://" + serviceName);

feign-reactive-core not found in custom repo

Hi, for some reason maven cannot download/find this repo, I added

<repositories>
    <repository>
      <id>bintray-kptfh-feign-reactive</id>
      <name>bintray</name>
      <url>https://dl.bintray.com/kptfh/feign-reactive</url>
    </repository>
  </repositories>

in the project level and

<dependency>
      <groupId>io.github.reactivefeign</groupId>
      <artifactId>feign-reactive-core</artifactId>
      <version>0.6.0</version>
    </dependency>
    <dependency>
      <groupId>io.github.reactivefeign</groupId>
      <artifactId>feign-reactive-cloud</artifactId>
      <version>0.6.0</version>
    </dependency>

in the dependencies section but for some reason I'm getting:
Could not resolve dependencies for project com.kgregorczyk.store_example:product:jar:0.0.2: Could not find artifact io.github.reactivefeign:feign-reactive:jar:0.6.0 in bintray-kptfh-feign-reactive

Here's my full pom file https://pastebin.com/pMHibgkw

@ReactiveFeignClient adds path + "/" even if not necessary

feign.reactor.version=1.0.30
Final request path: ReactiveFeignClient.path + "/" + GetMapping.value
If GetMapping.value is default "/" is added anyway.
The behavior is different from FeignClient

Example:

@GetMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
Result get(@RequestParam(value = "param") );
@ReactiveFeignClient(
path = "/my/path",
)

Expected (non reactive feign-client behaviour):
/my/path?param=...
Real: additional '/' is added after ReactiveFeignClient.path
/my/path/?param=...

@RequestLine("GET /icecream/flavors")

Hi, in the readme file you are using unknown annotations (at least, to me) like @RequestLine("GET /icecream/flavors") which dependency contains them?

How to properly build a client?

Hi, I'd like to create a simple client like this:

package com.kgregorczyk.store_example.library.clients;

import feign.Param;
import feign.RequestLine;
import reactivefeign.ReactiveFeign;
import reactor.core.publisher.Mono;

public interface CategoryFeignClient {

  @RequestLine("GET /{categoryId}/exists")
  Mono<Boolean> categoryExists(@Param("categoryId") String categoryId);

  static CategoryFeignClient createClient(String url) {
    return ReactiveFeign.builder().target(CategoryFeignClient.class, url);
  }
}

but I'm getting compilation errors saying that

incompatible types: java.lang.Class<com.kgregorczyk.store_example.library.clients.CategoryFeignClient> cannot be converted to java.lang.Class<java.lang.Object>

and i get it, it should be a class not an interface but how am I supposed to create a new instance of it ?

WebReactiveFeign.Builder not using webclient's httpClient configuration

Hello,

I'm currently constructing multiple feign clients using the WebReactiveFeign.Builder api. However this class is not using the httpClient configured before in the webclient. ( my httpClient use sslContext that trust all certs but the feignClient is not using it)
to be clear this is my configuration :

@Configuration
 public class FeignConfiguration {


   // ssl context trusting all certificates
  @Bean
  public SslContext sslContext() throws Exception {
      SslContext sslContext = SslContextBuilder.forClient()
          .trustManager(InsecureTrustManagerFactory.INSTANCE)
          .build();
      return sslContext;
  }

  @Bean
  public ClientHttpConnector httpConnector(SslContext sslContext) {
      HttpClient httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
      return new ReactorClientHttpConnector(httpClient);
  }

  @Bean
  public WebClient webClient(ClientHttpConnector httpConnector, ObjectMapper mapper) {
      ExchangeStrategies strategies = ExchangeStrategies
          .builder()
          .codecs(configurer -> {
              configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(mapper));
              configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(mapper));
          }).build();
      return WebClient.builder().clientConnector(httpConnector).exchangeStrategies(strategies).build();
  }

  @Bean
  public WebReactiveFeign.Builder reactiveFeignBuilder(WebClient webClient) {
      return WebReactiveFeign.builder(webClient.mutate());
  }
}

so when I use the bean WebReactiveFeign.Builder to create feignClients dynamically I got an ssl exception ( which means is not using my sslContext as configured in the httpClient -> webclient bean)

the ssl exception is :

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 

However if I pass the httpClient bean to the WebReactiveFeign.Builder directly ( as below ) it use the insecure sslContext without any exception :

@Bean
    public HttpClient httpConnector(SecurityProperties securityProps, SslContext sslContext) {
        HttpClient httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
        SecurityProperties.ProxyServer proxyServer = securityProps.getProxy();
        if (proxyServer != null) {
            httpClient.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP)
                .host(proxyServer.getHost())
                .port(proxyServer.getPort())
                .username(proxyServer.getUsername())
                .password(u -> proxyServer.getPassword()));
        }
        return httpClient;
    }

    @Bean
    public WebClient webClient(HttpClient httpClient, ObjectMapper mapper) {
        ExchangeStrategies strategies = ExchangeStrategies
            .builder()
            .codecs(configurer -> {
                configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(mapper));
                configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(mapper));
            }).build();
        return WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).exchangeStrategies(strategies).build();
    }

    @Bean
    public WebReactiveFeign.Builder reactiveFeignBuilder(WebClient webClient, HttpClient httpClient) {
        WebReactiveFeign.Builder<Object> builder = WebReactiveFeign.builder(webClient.mutate());
        builder.httpClient(httpClient);
        return builder;
    }

do you think it's WebReactiveFeign.Builder bug?

FYI I'm using :

    <dependency>
      <groupId>com.playtika.reactivefeign</groupId>
      <artifactId>feign-reactor-spring-cloud-starter</artifactId>
      <version>3.2.6</version>
      <type>pom</type>
    </dependency>

thank you in advance for your help ;)

Best regards,
Med

CloudReactiveFeign

Hi Sergii, we are doing a proof of concept with your feign-reactive library. Please, see below the two main issues we are having:

  1. Unable to set a custom RequestInterceptor bean.
  2. Unable to customize the default ErrorDecoder. See sample code below.

image

Any help or suggestion will be appreciated

Disable Hystrix not work

Hello, I am currently using your repo but unfortunately I can not disable Hystrix with the configuration: feign.hystrix.enabled = false.
there is always the circuit breaker that is active with the fallback.
I also can not disable the timeout.
could you help me please ?

Thanks

Support for Kotlin coroutine

Hi, what about writing an adapter for the kotlin coroutine compatibility?

package com.demo.feign

import kotlinx.coroutines.flow.Flow
import org.springframework.web.bind.annotation.GetMapping
import reactivefeign.spring.config.ReactiveFeignClient
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono

@ReactiveFeignClient(
    name = "helloClient",
    url = "http://localhost:8080"
)
interface HelloClient {

    @GetMapping("/hello")
    fun helloMono(): Mono<String>
    
    @GetMapping("/hello")
    suspend fun helloKotlinMono(): String

    @GetMapping("/hello")
    fun helloFlux(): Flux<String>

    @GetMapping("/hello")
    fun helloKotlinFlux(): Flow<String>
    
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.