Skip to content

Commit

Permalink
FEATURE: base feign-vertx on Vertx WebClient instead of bare vertx
Browse files Browse the repository at this point in the history
  • Loading branch information
hosuaby committed Feb 18, 2025
1 parent f91e528 commit 4014d29
Show file tree
Hide file tree
Showing 50 changed files with 2,083 additions and 299 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>feign-vertx</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>feign-micrometer</artifactId>
Expand Down
13 changes: 6 additions & 7 deletions vertx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Implementation of Feign on Vertx. 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 Vertx.
non-blocking WebClient of Vertx.

## Installation

Expand All @@ -14,7 +14,6 @@ non-blocking HTTP client of Vertx.
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-vertx</artifactId>
<version>14.0</version>
</dependency>
...
</dependencies>
Expand All @@ -23,14 +22,14 @@ non-blocking HTTP client of Vertx.
### With Gradle

```groovy
compile group: 'io.github.openfeign', name: 'feign-vertx', version: '14.0'
compile group: 'io.github.openfeign', name: 'feign-vertx'
```

## Compatibility

Feign | Vertx
---------------------- | ----------------------
14.x | 4.x
14.x | 4.x - 5.x

## Usage

Expand Down Expand Up @@ -62,15 +61,15 @@ interface IcecreamServiceApi {
Build the client :

```java
Vertx vertx = Vertx.vertx(); // get Vertx instance
WebClient webClient = WebClient.create(vertx); // create Vert.x WebClient

/* Create instance of your API */
IcecreamServiceApi icecreamApi = VertxFeign
.builder()
.vertx(vertx) // provide vertx instance
.webClient(webClient) // provide WebClient instance
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.target(IcecreamServiceApi.class, "http://www.icecreame.com");
.target(IcecreamServiceApi.class, "https://www.icecream.com");

/* Execute requests asynchronously */
Future<Collection<Flavor>> flavorsFuture = icecreamApi.getAvailableFlavors();
Expand Down
69 changes: 69 additions & 0 deletions vertx/feign-vertx/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright © 2012 The Feign Authors ([email protected])
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-vertx-parent</artifactId>
<version>13.6-SNAPSHOT</version>
</parent>

<artifactId>feign-vertx</artifactId>

<name>Feign Vertx</name>
<description>Implementation of Feign on Vertx web client.</description>

<properties>
<jackson.version>2.18.2</jackson.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${jackson.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>

<!-- Vertx -->
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>${vertx.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>${vertx.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@
import feign.querymap.FieldQueryMapEncoder;
import feign.vertx.VertxDelegatingContract;
import feign.vertx.VertxHttpClient;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.WebClient;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
Expand Down Expand Up @@ -92,7 +91,7 @@ public <T> T newInstance(final Target<T> target) {

/** VertxFeign builder. */
public static final class Builder extends Feign.Builder {
private Vertx vertx;
private WebClient webClient;
private final List<RequestInterceptor> requestInterceptors = new ArrayList<>();
private Logger.Level logLevel = Logger.Level.NONE;
private Contract contract = new VertxDelegatingContract(new Contract.Default());
Expand All @@ -103,10 +102,9 @@ public static final class Builder extends Feign.Builder {
private QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();
private List<Capability> capabilities = new ArrayList<>();
private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
private HttpClientOptions options = new HttpClientOptions();
private long timeout = -1;
private boolean decode404;
private UnaryOperator<HttpClientRequest> requestPreProcessor = UnaryOperator.identity();
private UnaryOperator<HttpRequest<Buffer>> requestPreProcessor = UnaryOperator.identity();

/** Unsupported operation. */
@Override
Expand All @@ -122,13 +120,13 @@ public Builder invocationHandlerFactory(
}

/**
* Sets a vertx instance to use to make the client.
* Sets a vertx WebClient.
*
* @param vertx vertx instance
* @param webClient vertx WebClient
* @return this builder
*/
public Builder vertx(final Vertx vertx) {
this.vertx = checkNotNull(vertx, "Argument vertx must be not null");
public Builder webClient(final WebClient webClient) {
this.webClient = checkNotNull(webClient, "Argument webClient must be not null");
return this;
}

Expand Down Expand Up @@ -263,34 +261,6 @@ public Builder errorDecoder(final ErrorDecoder errorDecoder) {
return this;
}

/**
* Sets request options using Vert.x {@link HttpClientOptions}.
*
* @param options {@code HttpClientOptions} for full customization of the underlying Vert.x
* {@link HttpClient}
* @return this builder
*/
public Builder options(final HttpClientOptions options) {
this.options = checkNotNull(options, "Argument options must be not null");
return this;
}

/**
* Sets request options using Feign {@link Request.Options}.
*
* @param options Feign {@code Request.Options} object
* @return this builder
*/
@Override
public Builder options(final Request.Options options) {
checkNotNull(options, "Argument options must be not null");
this.options =
new HttpClientOptions()
.setConnectTimeout(options.connectTimeoutMillis())
.setIdleTimeout(options.readTimeoutMillis());
return this;
}

/**
* Configures the amount of time in milliseconds after which if the request does not return any
* data within the timeout period an {@link java.util.concurrent.TimeoutException} fails the
Expand All @@ -307,22 +277,22 @@ public Builder timeout(long timeout) {
}

/**
* Defines operation to execute on each {@link HttpClientRequest} before it is sent. Used to
* make setup on request level.
* Defines operation to execute on each {@link HttpRequest} before it sent. Used to make setup
* on request level.
*
* <p>Example:
*
* <pre>
* var client = VertxFeign
* .builder()
* .vertx(vertx)
* .requestPreProcessor(req -&#62; req.putHeader("version", "v1"));
* .requestPreProcessor(req -&#62; req.ssl(true));
* </pre>
*
* @param requestPreProcessor operation to execute on each request
* @return updated request
*/
public Builder requestPreProcessor(UnaryOperator<HttpClientRequest> requestPreProcessor) {
public Builder requestPreProcessor(UnaryOperator<HttpRequest<Buffer>> requestPreProcessor) {
this.requestPreProcessor =
checkNotNull(requestPreProcessor, "Argument requestPreProcessor must be not null");
return this;
Expand Down Expand Up @@ -389,19 +359,24 @@ public <T> T target(final Target<T> target) {
return build().newInstance(target);
}

@Override
public Feign.Builder options(final Request.Options options) {
throw new UnsupportedOperationException(
"Options should be provided directly during construction of Vertx WebClient.");
}

@Override
public VertxFeign internalBuild() {
checkNotNull(this.vertx, "Vertx instance wasn't provided in VertxFeign builder");
checkNotNull(
this.webClient, "Vertx WebClient instance wasn't provided in VertxFeign builder");

final VertxHttpClient client =
new VertxHttpClient(vertx, options, timeout, requestPreProcessor);
final VertxHttpClient client = new VertxHttpClient(webClient, timeout, requestPreProcessor);
final VertxMethodHandler.Factory methodHandlerFactory =
new VertxMethodHandler.Factory(
client, retryer, requestInterceptors, logger, logLevel, decode404);
final ParseHandlersByName handlersByName =
new ParseHandlersByName(
contract,
options,
encoder,
decoder,
queryMapEncoder,
Expand All @@ -417,7 +392,6 @@ public VertxFeign internalBuild() {

private static final class ParseHandlersByName {
private final Contract contract;
private final HttpClientOptions options;
private final Encoder encoder;
private final Decoder decoder;
private final QueryMapEncoder queryMapEncoder;
Expand All @@ -427,15 +401,13 @@ private static final class ParseHandlersByName {

private ParseHandlersByName(
final Contract contract,
final HttpClientOptions options,
final Encoder encoder,
final Decoder decoder,
final QueryMapEncoder queryMapEncoder,
final List<Capability> capabilities,
final ErrorDecoder errorDecoder,
final VertxMethodHandler.Factory factory) {
this.contract = contract;
this.options = options;
this.factory = factory;
this.encoder = encoder;
this.decoder = decoder;
Expand Down
File renamed without changes.
Loading

0 comments on commit 4014d29

Please sign in to comment.