33
44The 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
10171010include-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
10221014include-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
10261018include-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