////
This guide is maintained in the main Quarkus repository
and pull requests should be submitted there:
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
////
= Using the REST Client Reactive

include::./attributes.adoc[]

This guide explains how to use the REST Client Reactive in order to interact with REST APIs.
REST Client Reactive is a non-blocking counterpart of the RESTEasy REST Client.

If your application uses a client and exposes REST endpoints, please use xref:resteasy-reactive.adoc[RESTEasy Reactive]
for the server part.

== Prerequisites

include::includes/devtools/prerequisites.adoc[]

== Solution

We recommend that you follow the instructions in the next sections and create the application step by step.
However, you can go right to the completed example.

Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive].

The solution is located in the `rest-client-reactive-quickstart` {quickstarts-tree-url}/rest-client-reactive-quickstart[directory].

== Creating the Maven project

First, we need a new project. Create a new project with the following command:

:create-app-artifact-id: rest-client-reactive-quickstart
:create-app-extensions: resteasy-reactive-jackson,rest-client-reactive-jackson
include::includes/devtools/create-app.adoc[]

This command generates the Maven project with a REST endpoint and imports:

* the `resteasy-reactive-jackson` extension for the REST server support. Use `resteasy-reactive` instead if you do not wish to use Jackson;
* the `rest-client-reactive-jackson` extension for the REST client support. Use `rest-client-reactive` instead if you do not wish to use Jackson

If you already have your Quarkus project configured, you can add the `rest-client-reactive-jackson` extension
to your project by running the following command in your project base directory:

:add-extension-extensions: rest-client-reactive-jackson
include::includes/devtools/extension-add.adoc[]

This will add the following to your build file:

[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
.pom.xml
----
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest-client-reactive-jackson</artifactId>
</dependency>
----

[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"]
.build.gradle
----
implementation("io.quarkus:quarkus-rest-client-reactive-jackson")
----

== Setting up the model

In this guide we will be demonstrating how to consume part of the REST API supplied by the link:https://stage.code.quarkus.io[stage.code.quarkus.io] service.
Our first order of business is to set up the model we will be using, in the form of a `Extension` POJO.

Create a `src/main/java/org/acme/rest/client/Extension.java` file and set the following content:

[source,java]
----
package org.acme.rest.client;

import java.util.List;

public class Extension {

    public String id;
    public String name;
    public String shortName;
    public List<String> keywords;

}
----

The model above is only a subset of the fields provided by the service, but it suffices for the purposes of this guide.

== Create the interface

Using the REST Client Reactive is as simple as creating an interface using the proper JAX-RS and MicroProfile annotations. In our case the interface should be created at `src/main/java/org/acme/rest/client/ExtensionsService.java` and have the following content:

[source, java]
----
package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import java.util.Set;

@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);
}
----

The `getById` method gives our code the ability to get an extension by id from the Code Quarkus API. The client will handle all the networking and marshalling leaving our code clean of such technical details.

The purpose of the annotations in the code above is the following:

* `@RegisterRestClient` allows Quarkus to know that this interface is meant to be available for
CDI injection as a REST Client
* `@Path`, `@GET` and `@PathParam` are the standard JAX-RS annotations used to define how to access the service

[NOTE]
====
When the `quarkus-rest-client-reactive-jackson` extension is installed, Quarkus will use the `application/json` media type
by default for most return values, unless the media type is explicitly set via `@Produces` or `@Consumes` annotations.

If you don't rely on the JSON default, it is heavily recommended to annotate your endpoints with the `@Produces` and `@Consumes` annotations to define precisely the expected content-types.
It will allow to narrow down the number of JAX-RS providers (which can be seen as converters) included in the native executable.
====

[WARNING]
====
The `getById` method above is a blocking call. It should not be invoked on the event loop.
The <<async-support>> section describes how to make non-blocking calls.
====

=== Path Parameters

If the GET request requires path parameters you can leverage the `@PathParam("parameter-name")` annotation instead of
(or in addition to) the `@QueryParam`. Path and query parameters can be combined, as required, as illustrated in the example below.

[source, java]
----
package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import java.util.Set;

@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    @Path("/stream/{stream}")
    Set<Extension> getByStream(@PathParam("stream") String stream, @QueryParam("id") String id);
}
----


== Create the configuration

In order to determine the base URL to which REST calls will be made, the REST Client uses configuration from `application.properties`.
The name of the property needs to follow a certain convention which is best displayed in the following code:

[source,properties]
----
# Your configuration properties
quarkus.rest-client."org.acme.rest.client.ExtensionsService".url=https://stage.code.quarkus.io/api # // <1>
----

<1> Having this configuration means that all requests performed using `org.acme.rest.client.ExtensionsService` will use `https://stage.code.quarkus.io/api` as the base URL.
Using the configuration above, calling the `getById` method of `ExtensionsService` with a value of `io.quarkus:quarkus-rest-client-reactive` would result in an HTTP GET request being made to `https://stage.code.quarkus.io/api/extensions?id=io.quarkus:quarkus-rest-client-reactive`.

Note that `org.acme.rest.client.ExtensionsService` _must_ match the fully qualified name of the `ExtensionsService` interface we created in the previous section.

To facilitate the configuration, you can use the `@RegisterRestClient` `configKey` property that allows to use different configuration root than the fully qualified name of your interface.

[source, java]
----

@RegisterRestClient(configKey="extensions-api")
public interface ExtensionsService {
    [...]
}
----

[source,properties]
----
# Your configuration properties
quarkus.rest-client.extensions-api.url=https://stage.code.quarkus.io/api
quarkus.rest-client.extensions-api.scope=javax.inject.Singleton
----

== Create the JAX-RS resource

Create the `src/main/java/org/acme/rest/client/ExtensionsResource.java` file with the following content:


[source,java]
----
package org.acme.rest.client;

import io.smallrye.common.annotation.Blocking;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.Set;

@Path("/extension")
public class ExtensionsResource {

    @RestClient // <1>
    ExtensionsService extensionsService;


    @GET
    @Path("/id/{id}")
    @Blocking // <2>
    public Set<Extension> id(String id) {
        return extensionsService.getById(id);
    }
}
----

There are two interesting parts in this listing:

<1> the client stub is injected with the `@RestClient` annotation instead of the usual CDI `@Inject`
<2> the call we are making with the client is blocking, hence we need the `@Blocking` annotation on the REST endpoint

== Programmatic client creation with RestClientBuilder

Instead of annotating the client with `@RegisterRestClient`, and injecting
a client with `@RestClient`, you can also create REST Client programmatically.
You do that with `RestClientBuilder`.

With this approach the client interface could look as follows:

[source,java]
----
package org.acme.rest.client;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import java.util.Set;

@Path("/extensions")
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);
}
----

And the service as follows:
[source,java]
----
package org.acme.rest.client;

import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.net.URI;
import java.util.Set;
import java.util.concurrent.CompletionStage;

@Path("/extension")
public class ExtensionsResource {

    private final ExtensionsService extensionsService;

    public ExtensionsResource() {
        extensionsService = RestClientBuilder.newBuilder()
            .baseUri(URI.create("https://stage.code.quarkus.io/api"))
            .build(ExtensionsService.class);
    }

    @GET
    @Path("/id/{id}")
    public Set<Extension> id(String id) {
        return extensionsService.getById(id);
    }
}
----

== Update the test

Next, we need to update the functional test to reflect the changes made to the endpoint.
Edit the `src/test/java/org/acme/rest/client/ExtensionsResourceTest.java` file and change the content of the test to:


[source, java]
----
package org.acme.rest.client;

import io.quarkus.test.junit.QuarkusTest;

import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.greaterThan;

@QuarkusTest
public class ExtensionsResourceTest {

    @Test
    public void testExtensionsIdEndpoint() {
        given()
            .when().get("/extension/id/io.quarkus:quarkus-rest-client-reactive")
            .then()
            .statusCode(200)
            .body("$.size()", is(1),
                "[0].id", is("io.quarkus:quarkus-rest-client-reactive"),
                "[0].name", is("REST Client Reactive"),
                "[0].keywords.size()", greaterThan(1),
                "[0].keywords", hasItem("rest-client"));
    }
}
----

The code above uses link:http://rest-assured.io/[REST Assured]'s link:https://github.com/rest-assured/rest-assured/wiki/GettingStarted#jsonpath[json-path] capabilities.


[#async-support]
== Async Support

To get the full power of the reactive nature of the client, you can use the non-blocking flavor of REST Client Reactive extension,
which comes with support for `CompletionStage` and `Uni`.
Let's see it in action by adding a `getByIdAsync` method in our `ExtensionsService` REST interface. The code should look like:

[source,java]
----
package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import java.util.Set;
import java.util.concurrent.CompletionStage;

@Path("/extensions")
@RegisterRestClient(configKey = "extensions-api")
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);

    @GET
    CompletionStage<Set<Extension>> getByIdAsync(@QueryParam("id") String id);
}
----

Open the `src/main/java/org/acme/rest/client/ExtensionsResource.java` file and update it with the following content:

[source,java]
----
package org.acme.rest.client;

import io.smallrye.common.annotation.Blocking;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.Set;
import java.util.concurrent.CompletionStage;

@Path("/extension")
public class ExtensionsResource {

    @RestClient
    ExtensionsService extensionsService;


    @GET
    @Path("/id/{id}")
    @Blocking
    public Set<Extension> id(String id) {
        return extensionsService.getById(id);
    }

    @GET
    @Path("/id-async/{id}")
    public CompletionStage<Set<Extension>> idAsync(String id) {
        return extensionsService.getByIdAsync(id);
    }
}
----

Please note that since the invocation is now non-blocking, we don't need the `@Blocking` annotation anymore on the endpoint.
This means that the `idAsync` method will be invoked on the event loop, i.e. will not get offloaded to a worker pool thread
and thus reducing hardware resource utilization.


To test asynchronous methods, add the test method below in `ExtensionsResourceTest`:
[source,java]
----
@Test
public void testExtensionIdAsyncEndpoint() {
    given()
        .when().get("/extension/id-async/io.quarkus:quarkus-rest-client-reactive")
        .then()
        .statusCode(200)
        .body("$.size()", is(1),
            "[0].id", is("io.quarkus:quarkus-rest-client-reactive"),
            "[0].name", is("REST Client Reactive"),
            "[0].keywords.size()", greaterThan(1),
            "[0].keywords", hasItem("rest-client"));
}
----

The `Uni` version is very similar:

[source, java]
----
package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.annotations.jaxrs.PathParam;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import java.util.Set;
import java.util.concurrent.CompletionStage;

@Path("/extensions")
@RegisterRestClient(configKey = "extensions-api")
public interface ExtensionsService {

    // ...

    @GET
    Uni<Set<Extension>> getByIdAsUni(@QueryParam("id") String id);
}
----

The `ExtensionsResource` becomes:

[source,java]
----
package org.acme.rest.client;

import io.smallrye.common.annotation.Blocking;
import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.Set;
import java.util.concurrent.CompletionStage;

@Path("/extension")
public class ExtensionsResource {

    @RestClient
    ExtensionsService extensionsService;


    // ...

    @GET
    @Path("/id-uni/{id}")
    public Uni<Set<Extension>> idUni(String id) {
        return extensionsService.getByIdAsUni(id);
    }
}
----

[TIP]
.Mutiny
====
The previous snippet uses Mutiny reactive types.
If you are not familiar with Mutiny, check xref:mutiny-primer.adoc[Mutiny - an intuitive reactive programming library].
====

When returning a `Uni`, every _subscription_ invokes the remote service.
It means you can re-send the request by re-subscribing on the `Uni`, or use a `retry` as follows:

[source, java]
----

@RestClient ExtensionsService extensionsService;

// ...

extensionsService.getByIdAsUni(id)
    .onFailure().retry().atMost(10);
----

If you use a `CompletionStage`, you would need to call the service's method to retry.
This difference comes from the laziness aspect of Mutiny and its subscription protocol.
More details about this can be found in https://smallrye.io/smallrye-mutiny/#_uni_and_multi[the Mutiny documentation].

== Custom headers support

There are a few ways in which you can specify custom headers for your REST calls:

- by registering a `ClientHeadersFactory` or a `ReactiveClientHeadersFactory` with the `@RegisterClientHeaders` annotation
- by specifying the value of the header with `@ClientHeaderParam`
- by specifying the value of the header by `@HeaderParam`

The code below demonstrates how to use each of these techniques:

[source, java]
----
package org.acme.rest.client;

import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import java.util.Set;
import java.util.concurrent.CompletionStage;

@Path("/extensions")
@RegisterRestClient
@RegisterClientHeaders(RequestUUIDHeaderFactory.class) // <1>
@ClientHeaderParam(name = "my-header", value = "constant-header-value") // <2>
@ClientHeaderParam(name = "computed-header", value = "{org.acme.rest.client.Util.computeHeader}") // <3>
public interface ExtensionsService {

    @GET
    @ClientHeaderParam(name = "header-from-properties", value = "${header.value}") // <4>
    Set<Extension> getById(@QueryParam("id") String id, @HeaderParam("jaxrs-style-header") String headerValue); // <5>
}
----

<1> There can be only one `ClientHeadersFactory` per class. With it, you can not only add custom headers, but you can also transform existing ones. See the `RequestUUIDHeaderFactory` class below for an example of the factory.
<2> `@ClientHeaderParam` can be used on the client interface and on methods. It can specify a constant header value...
<3> ... and a name of a method that should compute the value of the header. It can either be a static method or a default method in this interface
<4> ... as well as a value from your application's configuration
<5> ... or as a normal JAX-RS `@HeaderParam` annotated argument

[NOTE]
====
When using Kotlin, if default methods are going to be leveraged, then the Kotlin compiler needs to be configured to use Java's default interface capabilities.
See link:https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces[this] for more details.
====

A `ClientHeadersFactory` can look as follows:

[source, java]
----
package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import java.util.UUID;

@ApplicationScoped
public class RequestUUIDHeaderFactory implements ClientHeadersFactory {

    @Override
    public MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders, MultivaluedMap<String, String> clientOutgoingHeaders) {
        MultivaluedMap<String, String> result = new MultivaluedHashMap<>();
        result.add("X-request-uuid", UUID.randomUUID().toString());
        return result;
    }
}
----

As you see in the example above, you can make your `ClientHeadersFactory` implementation a CDI bean by
annotating it with a scope-defining annotation, such as `@Singleton`, `@ApplicationScoped`, etc.

To specify a value for `${header.value}`, simply put the following in your `application.properties`:

[source,properties]
----
header.value=value of the header
----

Also, there is a reactive flavor of `ClientHeadersFactory` that allows doing blocking operations. For example:

[source, java]
----
package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import java.util.UUID;

@ApplicationScoped
public class GetTokenReactiveClientHeadersFactory extends ReactiveClientHeadersFactory {

    @Inject
    Service service;

    @Override
    public Uni<MultivaluedMap<String, String>> getHeaders(
            MultivaluedMap<String, String> incomingHeaders,
            MultivaluedMap<String, String> clientOutgoingHeaders);
        return Uni.createFrom().item(() -> {
            MultivaluedHashMap<String, String> newHeaders = new MultivaluedHashMap<>();
            // perform blocking call
            newHeaders.add(HEADER_NAME, service.getToken());
            return newHeaders;
        });
    }
}
----

=== Default header factory

The `@RegisterClientHeaders` annotation can also be used without any custom factory specified. In that case the `DefaultClientHeadersFactoryImpl` factory will be used.
If you make a REST client call from a REST resource, this factory will propagate all the headers listed in `org.eclipse.microprofile.rest.client.propagateHeaders` configuration property from the resource request to the client request. Individual header names are comma-separated.
[source, java]
----
@Path("/extensions")
@RegisterRestClient
@RegisterClientHeaders
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);

    @GET
    CompletionStage<Set<Extension>> getByIdAsync(@QueryParam("id") String id);
}
----

[source,properties]
----
org.eclipse.microprofile.rest.client.propagateHeaders=Authorization,Proxy-Authorization
----

== Exception handling

The MicroProfile REST Client specification introduces the `org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper` whose purpose is to convert an HTTP response to an exception.

A simple example of implementing such a `ResponseExceptionMapper` for the `ExtensionsService` discussed above, could be:

[source, java]
----
public class MyResponseExceptionMapper implements ResponseExceptionMapper<RuntimeException> {

    @Override
    public RuntimeException toThrowable(Response response) {
        if (response.getStatus() == 500) {
            throw new RuntimeException("The remote service responded with HTTP 500");
        }
        return null;
    }
}
----

`ResponseExceptionMapper` also defines the `getPriority` method which is used in order to determine the priority with which `ResponseExceptionMapper` implementations will be called (implementations with a lower value for `getPriority` will be invoked first).
If `toThrowable` returns an exception, then that exception will be thrown. If `null` is returned, the next implementation of `ResponseExceptionMapper` in the chain will be called (if there is any).

The class as written above, would not be automatically be used by any REST Client. To make it available to every REST Client of the application, the class needs to be annotated with `@Provider` (as long as `quarkus.rest-client-reactive.provider-autodiscovery` is not set to `false`).
Alternatively, if the exception handling class should only apply to specific REST Client interfaces, you can either annotate the interfaces with `@RegisterProvider(MyResponseExceptionMapper.class)`, or register it using configuration using the `providers` property of the proper `quarkus.rest-client` configuration group.

=== Using @ClientExceptionMapper

A simpler way to convert HTTP response codes of 400 or above is to use the `@ClientExceptionMapper` annotation.

For the `ExtensionsService` REST Client interface defined above, an example use of `@ClientExceptionMapper` would be:

[source, java]
----
@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);

    @GET
    CompletionStage<Set<Extension>> getByIdAsync(@QueryParam("id") String id);

    @ClientExceptionMapper
    static RuntimeException toException(Response response) {
        if (response.getStatus() == 500) {
            return new RuntimeException("The remote service responded with HTTP 500");
        }
        return null;
    }
}
----

Naturally this handling is per REST Client. `@ClientExceptionMapper` uses the default priority if the `priority` attribute is not set and the normal rules of invoking all handlers in turn apply.

== Multipart Form support

REST Client Reactive support multipart messages.

=== Sending Multipart messages

REST Client Reactive allows sending data as multipart forms. This way you can for example
send files efficiently.

To send data as a multipart form, you need to create a class that would encapsulate all the fields
to be sent, e.g.

[source, java]
----
public class FormDto {
    @FormParam("file")
    @PartType(MediaType.APPLICATION_OCTET_STREAM)
    public File file;

    @FormParam("otherField")
    @PartType(MediaType.TEXT_PLAIN)
    public String textProperty;
}
----

The method that sends a form needs to specify multipart form data as the consumed media type, e.g.
[source, java]
----
    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/binary")
    String sendMultipart(@MultipartForm FormDto data);
----

Fields specified as `File`, `Path`, `byte[]` or `Buffer` are sent as files; as binary files for
`@PartType(MediaType.APPLICATION_OCTET_STREAM)`, as text files for other content types.
Other fields are sent as form attributes.

There are a few modes in which the form data can be encoded. By default,
Rest Client Reactive uses RFC1738.
You can override it by specifying the mode either on the client level,
by setting `io.quarkus.rest.client.multipart-post-encoder-mode` RestBuilder property
to the selected value of `HttpPostRequestEncoder.EncoderMode` or
by specifying `quarkus.rest-client.multipart-post-encoder-mode` in your
`application.properties`. Please note that the latter works only for
clients created with the `@RegisterRestClient` annotation.
All the available modes are described in the link:https://netty.io/4.1/api/io/netty/handler/codec/http/multipart/HttpPostRequestEncoder.EncoderMode.html[Netty documentation]

=== Receiving Multipart Messages
REST Client Reactive also supports receiving multipart messages.
As with sending, to parse a multipart response, you need to create a class that describes the response data, e.g.

[source,java]
----
public class FormDto {
    @RestForm // <1>
    @PartType(MediaType.APPLICATION_OCTET_STREAM)
    public File file;

    @FormParam("otherField") // <2>
    @PartType(MediaType.TEXT_PLAIN)
    public String textProperty;
}
----
<1> uses the shorthand `@RestForm` annotation to make a field as a part of a multipart form
<2> the standard `@FormParam` can also be used. It allows to override the name of the multipart part.

Then, create an interface method that corresponds to the call and make it return the `FormDto`:
[source,java]
----
    @GET
    @Produces(MediaType.MULTIPART_FORM_DATA)
    @Path("/get-file")
    FormDto data sendMultipart();
----

At the moment, multipart response support is subject to the following limitations:

- files sent in multipart responses can only be parsed to `File`, `Path` and `FileDownload`
- each field of the response type has to be annotated with `@PartType` - fields without this annotation are ignored

REST Client Reactive needs to know the classes used as multipart return types upfront. If you have an interface method that produces `multipart/form-data`, the return type will be discovered automatically. However, if you intend to use the `ClientBuilder` API to parse a response as multipart, you need to annotate your DTO class with `@MultipartForm`.

WARNING: The files you download are not automatically removed and can take up a lot of disk space. Consider removing the files when you are done working with them.

== Proxy support
REST Client Reactive supports sending requests through a proxy.
It honors the JVM settings for it but also allows to specify both:

* global client proxy settings, with `quarkus.rest-client.proxy-address`, `quarkus.rest-client.proxy-user`, `quarkus.rest-client.proxy-password`, `quarkus.rest-client.non-proxy-hosts`

* per-client proxy settings, with `quarkus.rest-client.<my-client>.proxy-address`, etc. These are applied only to clients injected with CDI, that is the ones created with `@RegisterRestClient`

If `proxy-address` is set on the client level, the client uses its specific proxy settings. No proxy settings are propagated from the global configuration or JVM properties.

If `proxy-address` is not set for the client but is set on the global level, the client uses the global settings.
Otherwise, the client uses the JVM settings.


An example configuration for setting proxy:

[source,properties]
----
# global proxy configuration is used for all clients
quarkus.rest-client.proxy-address=localhost:8182
quarkus.rest-client.proxy-user=<proxy user name>
quarkus.rest-client.proxy-password=<proxy password>
quarkus.rest-client.non-proxy-hosts=example.com

# per-client configuration overrides the global settings for a specific client
quarkus.rest-client.my-client.proxy-address=localhost:8183
quarkus.rest-client.my-client.proxy-user=<proxy user name>
quarkus.rest-client.my-client.proxy-password=<proxy password>
quarkus.rest-client.my-client.url=...
----

NOTE: MicroProfile REST Client specification does not allow setting proxy credentials. In order to specify proxy user and proxy password programmatically, you need to cast your `RestClientBuilder` to `RestClientBuilderImpl`.

== Package and run the application

Run the application with:

include::includes/devtools/dev.adoc[]

Open your browser to http://localhost:8080/extension/id/io.quarkus:quarkus-rest-client-reactive.

You should see a JSON object containing some basic information about this extension.

As usual, the application can be packaged using:

include::includes/devtools/build.adoc[]

And executed with `java -jar target/quarkus-app/quarkus-run.jar`.

You can also generate the native executable with:

include::includes/devtools/build-native.adoc[]

== Logging traffic
REST Client Reactive can log the requests it sends and the responses it receives.
To enable logging, add the `quarkus.rest-client.logging.scope` property to your `application.properties` and set it to:

* `request-response` to log the request and response contents, or
* `all` to also enable low level logging of the underlying libraries.

As HTTP messages can have large bodies, we limit the amount of body characters logged. The default limit is `100`, you can change it by specifying `quarkus.rest-client.logging.body-limit`.

NOTE: REST Client Reactive is logging the traffic with level DEBUG and does not alter logger properties. You may need to adjust your logger configuration to use this feature.

An example logging configuration:

[source,properties]
----
quarkus.rest-client.logging.scope=request-response
quarkus.rest-client.logging.body-limit=50

quarkus.log.category."org.jboss.resteasy.reactive.client.logging".level=DEBUG
----

== Mocking the client for tests
If you use a client injected with the `@RestClient` annotation, you can easily mock it for tests.
You can do it with Mockito's `@InjectMock` or with `QuarkusMock`.

This section shows how to replace your client with a mock. If you would like to get a more in-depth understanding of how mocking works in Quarkus, see the blog post on https://quarkus.io/blog/mocking/[Mocking CDI beans].

NOTE: Mocking does not work when using `@NativeImageTest` or `@QuarkusIntegrationTest`.

Let's assume you have the following client:
[source,java]
----
package io.quarkus.it.rest.client.main;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;


@Path("/")
@RegisterRestClient
public interface Client {
    @GET
    String get();
}
----


=== Mocking with InjectMock
The simplest approach to mock a client for tests is to use Mockito and `@InjectMock`.

First, add the following dependency to your application:

[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
.pom.xml
----
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5-mockito</artifactId>
    <scope>test</scope>
</dependency>
----

[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"]
.build.gradle
----
testImplementation("io.quarkus:quarkus-junit5-mockito")
----

Then, in your test you can simply use `@InjectMock` to create and inject a mock:

[source,java]
----
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.mockito.InjectMock;

@QuarkusTest
public class InjectMockTest {

    @InjectMock
    Client mock;

    @BeforeEach
    public void setUp() {
        when(mock.get()).thenReturn("MockAnswer");
    }

    @Test
    void doTest() {
        // ...
    }
}
----

=== Mocking with QuarkusMock
If Mockito doesn't meet your needs, you can create a mock programmatically using `QuarkusMock`, e.g.:

[source,java]
----
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusMock;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class QuarkusMockTest {

    @BeforeEach
    public void setUp() {
        Client customMock = new Client() { //<1>
            @Override
            public String get() {
                return "MockAnswer";
            }
        };
        QuarkusMock.installMockForType(customMock, Client.class, RestClient.LITERAL); // <2>
    }
    @Test
    void doTest() {
        // ...
    }
}
----

<1> here we use a manually created implementation of the client interface to replace the actual Client
<2> note that `RestClient.LITERAL` has to be passed as the last argument of the `installMockForType` method


== Using a Mock HTTP Server for tests
In some cases you may want to mock the remote endpoint - the HTTP server - instead of mocking the client itself.
This may be especially useful for native tests, or for programmatically created clients.

You can easily mock an HTTP Server with Wiremock.
The xref:rest-client.adoc#using-a-mock-http-server-for-tests[Wiremock section of the Quarkus - Using the REST Client]
describes how to set it up in detail.

== Known limitations
While the REST Client Reactive extension aims to be a drop-in replacement for the REST Client extension, there are some differences
and limitations:

- the default scope of the client for the new extension is `@ApplicationScoped` while the `quarkus-rest-client` defaults to `@Dependent`
To change this behavior, set the `quarkus.rest-client-reactive.scope` property to the fully qualified scope name.
- it is not possible to set `HostnameVerifier` or `SSLContext`
- a few things that don't make sense for a non-blocking implementations, such as setting the `ExecutorService`, don't work



== Further reading

 * link:https://download.eclipse.org/microprofile/microprofile-rest-client-2.0/microprofile-rest-client-spec-2.0.html[MicroProfile Rest Client specification]
