Polishing reference docs for HTTP Service clients
See gh-34912
This commit is contained in:
parent
05d59271d2
commit
81626b0734
|
@ -3,10 +3,10 @@
|
||||||
|
|
||||||
The Spring Framework provides the following choices for making calls to REST endpoints:
|
The Spring Framework provides the following choices for making calls to REST endpoints:
|
||||||
|
|
||||||
* xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] - synchronous client with a fluent API.
|
* xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] -- synchronous client with a fluent API
|
||||||
* xref:integration/rest-clients.adoc#rest-webclient[`WebClient`] - non-blocking, reactive client with fluent API.
|
* xref:integration/rest-clients.adoc#rest-webclient[`WebClient`] -- non-blocking, reactive client with fluent API
|
||||||
* xref:integration/rest-clients.adoc#rest-resttemplate[`RestTemplate`] - synchronous client with template method API.
|
* xref:integration/rest-clients.adoc#rest-resttemplate[`RestTemplate`] -- synchronous client with template method API
|
||||||
* xref:integration/rest-clients.adoc#rest-http-interface[HTTP Interface] - annotated interface with generated, dynamic proxy implementation.
|
* xref:integration/rest-clients.adoc#rest-http-interface[HTTP Interface Clients] -- annotated interface backed by generated proxy
|
||||||
|
|
||||||
|
|
||||||
[[rest-restclient]]
|
[[rest-restclient]]
|
||||||
|
@ -857,15 +857,17 @@ It can be used to migrate from the latter to the former.
|
||||||
|
|
||||||
|
|
||||||
[[rest-http-interface]]
|
[[rest-http-interface]]
|
||||||
== HTTP Interface
|
== HTTP Interface Clients
|
||||||
|
|
||||||
The Spring Framework lets you define an HTTP service as a Java interface with
|
You can define an HTTP Service as a Java interface with `@HttpExchange` methods, and use
|
||||||
`@HttpExchange` methods. You can pass such an interface to `HttpServiceProxyFactory`
|
`HttpServiceProxyFactory` to create a client proxy from it for remote access over HTTP via
|
||||||
to create a proxy which performs requests through an HTTP client such as `RestClient`
|
`RestClient`, `WebClient`, or `RestTemplate`. On the server side, an `@Controller` class
|
||||||
or `WebClient`. You can also implement the interface from an `@Controller` for server
|
can implement the same interface to handle requests with
|
||||||
request handling.
|
xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-httpexchange-annotation[@HttpExchange]
|
||||||
|
controller methods.
|
||||||
|
|
||||||
Start by creating the interface with `@HttpExchange` methods:
|
|
||||||
|
First, create the Java interface:
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
[source,java,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
@ -879,43 +881,7 @@ Start by creating the interface with `@HttpExchange` methods:
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
Now you can create a proxy that performs requests when methods are called.
|
Optionally, use `@HttpExchange` at the type level to declare common attributes for all methods:
|
||||||
|
|
||||||
For `RestClient`:
|
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build();
|
|
||||||
RestClientAdapter adapter = RestClientAdapter.create(restClient);
|
|
||||||
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
|
|
||||||
|
|
||||||
RepositoryService service = factory.createClient(RepositoryService.class);
|
|
||||||
----
|
|
||||||
|
|
||||||
For `WebClient`:
|
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
WebClient webClient = WebClient.builder().baseUrl("https://api.github.com/").build();
|
|
||||||
WebClientAdapter adapter = WebClientAdapter.create(webClient);
|
|
||||||
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
|
|
||||||
|
|
||||||
RepositoryService service = factory.createClient(RepositoryService.class);
|
|
||||||
----
|
|
||||||
|
|
||||||
For `RestTemplate`:
|
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
|
||||||
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("https://api.github.com/"));
|
|
||||||
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
|
|
||||||
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
|
|
||||||
|
|
||||||
RepositoryService service = factory.createClient(RepositoryService.class);
|
|
||||||
----
|
|
||||||
|
|
||||||
`@HttpExchange` is supported at the type level where it applies to all methods:
|
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
[source,java,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
@ -933,15 +899,46 @@ For `RestTemplate`:
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
||||||
|
Next, configure the client and create the `HttpServiceProxyFactory`:
|
||||||
|
|
||||||
|
[source,java,indent=0,subs="verbatim,quotes"]
|
||||||
|
----
|
||||||
|
// Using RestClient...
|
||||||
|
|
||||||
|
RestClient restClient = RestClient.create("...");
|
||||||
|
RestClientAdapter adapter = RestClientAdapter.create(restClient);
|
||||||
|
|
||||||
|
// or WebClient...
|
||||||
|
|
||||||
|
WebClient webClient = WebClient.create("...");
|
||||||
|
WebClientAdapter adapter = WebClientAdapter.create(webClient);
|
||||||
|
|
||||||
|
// or RestTemplate...
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
|
||||||
|
|
||||||
|
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
|
||||||
|
----
|
||||||
|
|
||||||
|
Now, you're ready to create client proxies:
|
||||||
|
|
||||||
|
[source,java,indent=0,subs="verbatim,quotes"]
|
||||||
|
----
|
||||||
|
RepositoryService service = factory.createClient(RepositoryService.class);
|
||||||
|
// Use service methods for remote calls...
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[rest-http-interface-method-parameters]]
|
[[rest-http-interface-method-parameters]]
|
||||||
=== Method Parameters
|
=== Method Parameters
|
||||||
|
|
||||||
Annotated, HTTP exchange methods support flexible method signatures with the following
|
`@HttpExchange` methods support flexible method signatures with the following inputs:
|
||||||
method parameters:
|
|
||||||
|
|
||||||
[cols="1,2", options="header"]
|
[cols="1,2", options="header"]
|
||||||
|===
|
|===
|
||||||
| Method argument | Description
|
| Method parameter | Description
|
||||||
|
|
||||||
| `URI`
|
| `URI`
|
||||||
| Dynamically set the URL for the request, overriding the annotation's `url` attribute.
|
| Dynamically set the URL for the request, overriding the annotation's `url` attribute.
|
||||||
|
@ -1005,26 +1002,26 @@ parameter annotation) is set to `false`, or the parameter is marked optional as
|
||||||
|
|
||||||
|
|
||||||
[[rest-http-interface.custom-resolver]]
|
[[rest-http-interface.custom-resolver]]
|
||||||
=== Custom argument resolver
|
=== Custom Arguments
|
||||||
|
|
||||||
For more complex cases, HTTP interfaces do not support `RequestEntity` types as method parameters.
|
You can configure a custom `HttpServiceArgumentResolver`. The example interface below
|
||||||
This would take over the entire HTTP request and not improve the semantics of the interface.
|
uses a custom `Search` method parameter type:
|
||||||
Instead of adding many method parameters, developers can combine them into a custom type
|
|
||||||
and configure a dedicated `HttpServiceArgumentResolver` implementation.
|
|
||||||
|
|
||||||
In the following HTTP interface, we are using a custom `Search` type as a parameter:
|
|
||||||
|
|
||||||
include-code::./CustomHttpServiceArgumentResolver[tag=httpinterface,indent=0]
|
include-code::./CustomHttpServiceArgumentResolver[tag=httpinterface,indent=0]
|
||||||
|
|
||||||
We can implement our own `HttpServiceArgumentResolver` that supports our custom `Search` type
|
A custom argument resolver could be implemented like this:
|
||||||
and writes its data in the outgoing HTTP request.
|
|
||||||
|
|
||||||
include-code::./CustomHttpServiceArgumentResolver[tag=argumentresolver,indent=0]
|
include-code::./CustomHttpServiceArgumentResolver[tag=argumentresolver,indent=0]
|
||||||
|
|
||||||
Finally, we can use this argument resolver during the setup and use our HTTP interface.
|
To configure the custom argument resolver:
|
||||||
|
|
||||||
include-code::./CustomHttpServiceArgumentResolver[tag=usage,indent=0]
|
include-code::./CustomHttpServiceArgumentResolver[tag=usage,indent=0]
|
||||||
|
|
||||||
|
TIP: By default, `RequestEntity` is not supported as a method parameter, instead encouraging
|
||||||
|
the use of more fine-grained method parameters for individual parts of the request.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[rest-http-interface-return-values]]
|
[[rest-http-interface-return-values]]
|
||||||
=== Return Values
|
=== Return Values
|
||||||
|
|
||||||
|
@ -1101,61 +1098,35 @@ underlying HTTP client, which operates at a lower level and provides more contro
|
||||||
[[rest-http-interface-exceptions]]
|
[[rest-http-interface-exceptions]]
|
||||||
=== Error Handling
|
=== Error Handling
|
||||||
|
|
||||||
To customize error response handling, you need to configure the underlying HTTP client.
|
To customize error handling for HTTP Service client proxies, you can configure the
|
||||||
|
underlying client as needed. By default, clients raise an exception for 4xx and 5xx HTTP
|
||||||
For `RestClient`:
|
status codes. To customize this, register a response status handler that applies to all
|
||||||
|
responses performed through the client as follows:
|
||||||
By default, `RestClient` raises `RestClientException` for 4xx and 5xx HTTP status codes.
|
|
||||||
To customize this, register a response status handler that applies to all responses
|
|
||||||
performed through the client:
|
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
[source,java,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
// For RestClient
|
||||||
RestClient restClient = RestClient.builder()
|
RestClient restClient = RestClient.builder()
|
||||||
.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
|
.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
RestClientAdapter adapter = RestClientAdapter.create(restClient);
|
RestClientAdapter adapter = RestClientAdapter.create(restClient);
|
||||||
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
|
|
||||||
----
|
|
||||||
|
|
||||||
For more details and options, such as suppressing error status codes, see the Javadoc of
|
// or for WebClient...
|
||||||
`defaultStatusHandler` in `RestClient.Builder`.
|
|
||||||
|
|
||||||
For `WebClient`:
|
|
||||||
|
|
||||||
By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status codes.
|
|
||||||
To customize this, register a response status handler that applies to all responses
|
|
||||||
performed through the client:
|
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
WebClient webClient = WebClient.builder()
|
WebClient webClient = WebClient.builder()
|
||||||
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
|
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
WebClientAdapter adapter = WebClientAdapter.create(webClient);
|
WebClientAdapter adapter = WebClientAdapter.create(webClient);
|
||||||
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(adapter).build();
|
|
||||||
----
|
|
||||||
|
|
||||||
For more details and options, such as suppressing error status codes, see the Javadoc of
|
// or for RestTemplate...
|
||||||
`defaultStatusHandler` in `WebClient.Builder`.
|
|
||||||
|
|
||||||
For `RestTemplate`:
|
|
||||||
|
|
||||||
By default, `RestTemplate` raises `RestClientException` for 4xx and 5xx HTTP status codes.
|
|
||||||
To customize this, register an error handler that applies to all responses
|
|
||||||
performed through the client:
|
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
restTemplate.setErrorHandler(myErrorHandler);
|
restTemplate.setErrorHandler(myErrorHandler);
|
||||||
|
|
||||||
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
|
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
|
||||||
|
|
||||||
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
|
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
|
||||||
----
|
----
|
||||||
|
|
||||||
For more details and options, see the Javadoc of `setErrorHandler` in `RestTemplate` and
|
For more details and options such as suppressing error status codes, see the reference
|
||||||
the `ResponseErrorHandler` hierarchy.
|
documentation for each client, as well as the Javadoc of `defaultStatusHandler` in
|
||||||
|
`RestClient.Builder` or `WebClient.Builder`, and the `setErrorHandler` of `RestTemplate`.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue