Skip to content

Commit 81626b0

Browse files
committed
Polishing reference docs for HTTP Service clients
See gh-34912
1 parent 05d5927 commit 81626b0

File tree

1 file changed

+64
-93
lines changed

1 file changed

+64
-93
lines changed

framework-docs/modules/ROOT/pages/integration/rest-clients.adoc

Lines changed: 64 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44
The Spring Framework provides the following choices for making calls to REST endpoints:
55

6-
* xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] - synchronous client with a fluent API.
7-
* xref:integration/rest-clients.adoc#rest-webclient[`WebClient`] - non-blocking, reactive client with fluent API.
8-
* xref:integration/rest-clients.adoc#rest-resttemplate[`RestTemplate`] - synchronous client with template method API.
9-
* xref:integration/rest-clients.adoc#rest-http-interface[HTTP Interface] - annotated interface with generated, dynamic proxy implementation.
6+
* xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] -- synchronous client with a fluent API
7+
* xref:integration/rest-clients.adoc#rest-webclient[`WebClient`] -- non-blocking, reactive client with fluent API
8+
* xref:integration/rest-clients.adoc#rest-resttemplate[`RestTemplate`] -- synchronous client with template method API
9+
* xref:integration/rest-clients.adoc#rest-http-interface[HTTP Interface Clients] -- annotated interface backed by generated proxy
1010

1111

1212
[[rest-restclient]]
@@ -857,15 +857,17 @@ It can be used to migrate from the latter to the former.
857857

858858

859859
[[rest-http-interface]]
860-
== HTTP Interface
860+
== HTTP Interface Clients
861861

862-
The Spring Framework lets you define an HTTP service as a Java interface with
863-
`@HttpExchange` methods. You can pass such an interface to `HttpServiceProxyFactory`
864-
to create a proxy which performs requests through an HTTP client such as `RestClient`
865-
or `WebClient`. You can also implement the interface from an `@Controller` for server
866-
request handling.
862+
You can define an HTTP Service as a Java interface with `@HttpExchange` methods, and use
863+
`HttpServiceProxyFactory` to create a client proxy from it for remote access over HTTP via
864+
`RestClient`, `WebClient`, or `RestTemplate`. On the server side, an `@Controller` class
865+
can implement the same interface to handle requests with
866+
xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-httpexchange-annotation[@HttpExchange]
867+
controller methods.
867868

868-
Start by creating the interface with `@HttpExchange` methods:
869+
870+
First, create the Java interface:
869871

870872
[source,java,indent=0,subs="verbatim,quotes"]
871873
----
@@ -879,69 +881,64 @@ Start by creating the interface with `@HttpExchange` methods:
879881
}
880882
----
881883

882-
Now you can create a proxy that performs requests when methods are called.
883-
884-
For `RestClient`:
884+
Optionally, use `@HttpExchange` at the type level to declare common attributes for all methods:
885885

886886
[source,java,indent=0,subs="verbatim,quotes"]
887887
----
888-
RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build();
889-
RestClientAdapter adapter = RestClientAdapter.create(restClient);
890-
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
888+
@HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json")
889+
public interface RepositoryService {
891890
892-
RepositoryService service = factory.createClient(RepositoryService.class);
893-
----
891+
@GetExchange
892+
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
894893
895-
For `WebClient`:
894+
@PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
895+
void updateRepository(@PathVariable String owner, @PathVariable String repo,
896+
@RequestParam String name, @RequestParam String description, @RequestParam String homepage);
896897
897-
[source,java,indent=0,subs="verbatim,quotes"]
898+
}
898899
----
899-
WebClient webClient = WebClient.builder().baseUrl("https://api.github.com/").build();
900-
WebClientAdapter adapter = WebClientAdapter.create(webClient);
901-
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
902900

903-
RepositoryService service = factory.createClient(RepositoryService.class);
904-
----
905901

906-
For `RestTemplate`:
902+
Next, configure the client and create the `HttpServiceProxyFactory`:
907903

908904
[source,java,indent=0,subs="verbatim,quotes"]
909905
----
906+
// Using RestClient...
907+
908+
RestClient restClient = RestClient.create("...");
909+
RestClientAdapter adapter = RestClientAdapter.create(restClient);
910+
911+
// or WebClient...
912+
913+
WebClient webClient = WebClient.create("...");
914+
WebClientAdapter adapter = WebClientAdapter.create(webClient);
915+
916+
// or RestTemplate...
917+
910918
RestTemplate restTemplate = new RestTemplate();
911-
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("https://api.github.com/"));
912919
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
913-
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
914920
915-
RepositoryService service = factory.createClient(RepositoryService.class);
921+
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
916922
----
917923

918-
`@HttpExchange` is supported at the type level where it applies to all methods:
924+
Now, you're ready to create client proxies:
919925

920926
[source,java,indent=0,subs="verbatim,quotes"]
921927
----
922-
@HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json")
923-
public interface RepositoryService {
924-
925-
@GetExchange
926-
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
927-
928-
@PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
929-
void updateRepository(@PathVariable String owner, @PathVariable String repo,
930-
@RequestParam String name, @RequestParam String description, @RequestParam String homepage);
931-
932-
}
928+
RepositoryService service = factory.createClient(RepositoryService.class);
929+
// Use service methods for remote calls...
933930
----
934931

935932

933+
936934
[[rest-http-interface-method-parameters]]
937935
=== Method Parameters
938936

939-
Annotated, HTTP exchange methods support flexible method signatures with the following
940-
method parameters:
937+
`@HttpExchange` methods support flexible method signatures with the following inputs:
941938

942939
[cols="1,2", options="header"]
943940
|===
944-
| Method argument | Description
941+
| Method parameter | Description
945942

946943
| `URI`
947944
| 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
10051002

10061003

10071004
[[rest-http-interface.custom-resolver]]
1008-
=== Custom argument resolver
1005+
=== Custom Arguments
10091006

1010-
For more complex cases, HTTP interfaces do not support `RequestEntity` types as method parameters.
1011-
This would take over the entire HTTP request and not improve the semantics of the interface.
1012-
Instead of adding many method parameters, developers can combine them into a custom type
1013-
and configure a dedicated `HttpServiceArgumentResolver` implementation.
1014-
1015-
In the following HTTP interface, we are using a custom `Search` type as a parameter:
1007+
You can configure a custom `HttpServiceArgumentResolver`. The example interface below
1008+
uses a custom `Search` method parameter type:
10161009

10171010
include-code::./CustomHttpServiceArgumentResolver[tag=httpinterface,indent=0]
10181011

1019-
We can implement our own `HttpServiceArgumentResolver` that supports our custom `Search` type
1020-
and writes its data in the outgoing HTTP request.
1012+
A custom argument resolver could be implemented like this:
10211013

10221014
include-code::./CustomHttpServiceArgumentResolver[tag=argumentresolver,indent=0]
10231015

1024-
Finally, we can use this argument resolver during the setup and use our HTTP interface.
1016+
To configure the custom argument resolver:
10251017

10261018
include-code::./CustomHttpServiceArgumentResolver[tag=usage,indent=0]
10271019

1020+
TIP: By default, `RequestEntity` is not supported as a method parameter, instead encouraging
1021+
the use of more fine-grained method parameters for individual parts of the request.
1022+
1023+
1024+
10281025
[[rest-http-interface-return-values]]
10291026
=== Return Values
10301027

@@ -1101,61 +1098,35 @@ underlying HTTP client, which operates at a lower level and provides more contro
11011098
[[rest-http-interface-exceptions]]
11021099
=== Error Handling
11031100

1104-
To customize error response handling, you need to configure the underlying HTTP client.
1105-
1106-
For `RestClient`:
1107-
1108-
By default, `RestClient` raises `RestClientException` for 4xx and 5xx HTTP status codes.
1109-
To customize this, register a response status handler that applies to all responses
1110-
performed through the client:
1101+
To customize error handling for HTTP Service client proxies, you can configure the
1102+
underlying client as needed. By default, clients raise an exception for 4xx and 5xx HTTP
1103+
status codes. To customize this, register a response status handler that applies to all
1104+
responses performed through the client as follows:
11111105

11121106
[source,java,indent=0,subs="verbatim,quotes"]
11131107
----
1108+
// For RestClient
11141109
RestClient restClient = RestClient.builder()
11151110
.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
11161111
.build();
1117-
11181112
RestClientAdapter adapter = RestClientAdapter.create(restClient);
1119-
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
1120-
----
1121-
1122-
For more details and options, such as suppressing error status codes, see the Javadoc of
1123-
`defaultStatusHandler` in `RestClient.Builder`.
1124-
1125-
For `WebClient`:
1126-
1127-
By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status codes.
1128-
To customize this, register a response status handler that applies to all responses
1129-
performed through the client:
11301113
1131-
[source,java,indent=0,subs="verbatim,quotes"]
1132-
----
1114+
// or for WebClient...
11331115
WebClient webClient = WebClient.builder()
11341116
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
11351117
.build();
1136-
11371118
WebClientAdapter adapter = WebClientAdapter.create(webClient);
1138-
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(adapter).build();
1139-
----
11401119
1141-
For more details and options, such as suppressing error status codes, see the Javadoc of
1142-
`defaultStatusHandler` in `WebClient.Builder`.
1143-
1144-
For `RestTemplate`:
1145-
1146-
By default, `RestTemplate` raises `RestClientException` for 4xx and 5xx HTTP status codes.
1147-
To customize this, register an error handler that applies to all responses
1148-
performed through the client:
1149-
1150-
[source,java,indent=0,subs="verbatim,quotes"]
1151-
----
1120+
// or for RestTemplate...
11521121
RestTemplate restTemplate = new RestTemplate();
11531122
restTemplate.setErrorHandler(myErrorHandler);
1154-
1123+
11551124
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
1125+
11561126
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
11571127
----
11581128

1159-
For more details and options, see the Javadoc of `setErrorHandler` in `RestTemplate` and
1160-
the `ResponseErrorHandler` hierarchy.
1129+
For more details and options such as suppressing error status codes, see the reference
1130+
documentation for each client, as well as the Javadoc of `defaultStatusHandler` in
1131+
`RestClient.Builder` or `WebClient.Builder`, and the `setErrorHandler` of `RestTemplate`.
11611132

0 commit comments

Comments
 (0)