REST クライアント

Spring Framework は、REST エンドポイントを呼び出すために次の選択肢を提供します。

  • RestClient - 流れるような API を備えた同期クライアント。

  • WebClient - 流れるような API を備えたノンブロッキングでリアクティブなクライアント。

  • RestTemplate - テンプレートメソッド API を使用した同期クライアント。

  • HTTP インターフェース - 生成された動的プロキシ実装を備えたアノテーション付きインターフェース。

RestClient

RestClient は、最新の流れるような API を提供する同期 HTTP クライアントです。これは、Java オブジェクトから HTTP リクエストへの便利な変換、および HTTP レスポンスからのオブジェクトの作成を可能にする HTTP ライブラリの抽象化を提供します。

RestClient の作成

RestClient は、静的 create メソッドの 1 つを使用して作成されます。builder() を使用して、使用する HTTP ライブラリ ( クライアントリクエストファクトリを参照) や使用するメッセージコンバーター (HTTP メッセージ変換を参照) の指定、デフォルトの URI、デフォルトのパス変数、デフォルトのリクエストヘッダーの設定など、追加のオプションを備えたビルダーを取得することもできます。uriBuilderFactory、またはインターセプタとイニシャライザーの登録。

RestClient を作成 (またはビルド) すると、複数のスレッドで安全に使用できるようになります。

次のサンプルは、デフォルトの RestClient を作成する方法と、カスタムの RestClient を構築する方法を示しています。

  • Java

  • Kotlin

RestClient defaultClient = RestClient.create();

RestClient customClient = RestClient.builder()
  .requestFactory(new HttpComponentsClientHttpRequestFactory())
  .messageConverters(converters -> converters.add(new MyCustomMessageConverter()))
  .baseUrl("https://example.com")
  .defaultUriVariables(Map.of("variable", "foo"))
  .defaultHeader("My-Header", "Foo")
  .defaultCookie("My-Cookie", "Bar")
  .requestInterceptor(myCustomInterceptor)
  .requestInitializer(myCustomInitializer)
  .build();
val defaultClient = RestClient.create()

val customClient = RestClient.builder()
  .requestFactory(HttpComponentsClientHttpRequestFactory())
  .messageConverters { converters -> converters.add(MyCustomMessageConverter()) }
  .baseUrl("https://example.com")
  .defaultUriVariables(mapOf("variable" to "foo"))
  .defaultHeader("My-Header", "Foo")
  .defaultCookie("My-Cookie", "Bar")
  .requestInterceptor(myCustomInterceptor)
  .requestInitializer(myCustomInitializer)
  .build()

RestClient を使用する

RestClient で HTTP リクエストを作成する場合、最初に指定するのは、使用する HTTP メソッドです。これは、method(HttpMethod) または便利なメソッド get()head()post() などを使用して実行できます。

リクエスト URL

次に、uri メソッドを使用してリクエスト URI を指定できます。この手順はオプションであり、RestClient がデフォルトの URI で構成されている場合はスキップできます。URL は通常、オプションの URI テンプレート変数を使用して String として指定されます。次の例では、example.com/orders/42 (英語) への GET リクエストを構成します。

  • Java

  • Kotlin

int id = 42;
restClient.get()
  .uri("https://example.com/orders/{id}", id)
  ....
val id = 42
restClient.get()
  .uri("https://example.com/orders/{id}", id)
  ...

関数は、リクエストパラメーターの指定など、追加の制御にも使用できます。

文字列 URL はデフォルトでエンコードされますが、カスタム uriBuilderFactory を使用してクライアントを構築することでこれを変更できます。URL は関数または java.net.URI として提供することもできますが、どちらもエンコードされません。URI の操作とエンコードの詳細については、URI リンクを参照してください。

リクエストのヘッダーと本文

必要に応じて、header(String, String)headers(Consumer<HttpHeaders>、または便利なメソッド accept(MediaType…​)acceptCharset(Charset…​) などを使用してリクエストヘッダーを追加することで、HTTP リクエストを操作できます。本文 (POSTPUTPATCH) を含むことができる HTTP リクエストの場合、追加のメソッド contentType(MediaType) および contentLength(long) を使用できます。

リクエスト本文自体は、内部で HTTP メッセージ変換を使用する body(Object) によって設定できます。あるいは、ParameterizedTypeReference を使用してリクエスト本文を設定し、ジェネリクスを使用できるようにすることもできます。最後に、本体を OutputStream に書き込むコールバック関数に設定できます。

レスポンスの取得

リクエストが設定されると、retrieve() を呼び出して HTTP レスポンスにアクセスします。レスポンス本文には、リストなどのパラメーター化された型の body(Class) または body(ParameterizedTypeReference) を使用してアクセスできます。body メソッドは、レスポンスコンテンツをさまざまな型に変換します。たとえば、バイトは String に変換でき、JSON は Jackson を使用してオブジェクトに変換できます ( HTTP メッセージ変換を参照)。

レスポンスを ResponseEntity に変換して、本文だけでなくレスポンスヘッダーにもアクセスできるようにすることもできます。

このサンプルは、RestClient を使用して単純な GET リクエストを実行する方法を示します。

  • Java

  • Kotlin

String result = restClient.get() (1)
  .uri("https://example.com") (2)
  .retrieve() (3)
  .body(String.class); (4)

System.out.println(result); (5)
1GET リクエストを設定する
2 接続先の URL を指定する
3 レスポンスを取得する
4 レスポンスを文字列に変換する
5 結果を出力する
val result= restClient.get() (1)
  .uri("https://example.com") (2)
  .retrieve() (3)
  .body<String>() (4)

println(result) (5)
1GET リクエストを設定する
2 接続先の URL を指定する
3 レスポンスを取得する
4 レスポンスを文字列に変換する
5 結果を出力する

レスポンスステータスコードとヘッダーへのアクセスは、ResponseEntity を通じて提供されます。

  • Java

  • Kotlin

ResponseEntity<String> result = restClient.get() (1)
  .uri("https://example.com") (1)
  .retrieve()
  .toEntity(String.class); (2)

System.out.println("Response status: " + result.getStatusCode()); (3)
System.out.println("Response headers: " + result.getHeaders()); (3)
System.out.println("Contents: " + result.getBody()); (3)
1 指定された URL に対する GET リクエストを設定します
2 レスポンスを ResponseEntity に変換します
3 結果を出力する
val result = restClient.get() (1)
  .uri("https://example.com") (1)
  .retrieve()
  .toEntity<String>() (2)

println("Response status: " + result.statusCode) (3)
println("Response headers: " + result.headers) (3)
println("Contents: " + result.body) (3)
1 指定された URL に対する GET リクエストを設定します
2 レスポンスを ResponseEntity に変換します
3 結果を出力する

RestClient は、Jackson ライブラリを使用して JSON をオブジェクトに変換できます。このサンプルでは URI 変数が使用されており、Accept ヘッダーが JSON に設定されていることに注意してください。

  • Java

  • Kotlin

int id = ...;
Pet pet = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id) (1)
  .accept(APPLICATION_JSON) (2)
  .retrieve()
  .body(Pet.class); (3)
1URI 変数の使用
2Accept ヘッダーを application/json に設定します
3JSON レスポンスを Pet ドメインオブジェクトに変換します
val id = ...
val pet = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id) (1)
  .accept(APPLICATION_JSON) (2)
  .retrieve()
  .body<Pet>() (3)
1URI 変数の使用
2Accept ヘッダーを application/json に設定します
3JSON レスポンスを Pet ドメインオブジェクトに変換します

次のサンプルでは、RestClient を使用して JSON を含む POST リクエストを実行します。JSON は再び Jackson を使用して変換されます。

  • Java

  • Kotlin

Pet pet = ... (1)
ResponseEntity<Void> response = restClient.post() (2)
  .uri("https://petclinic.example.com/pets/new") (2)
  .contentType(APPLICATION_JSON) (3)
  .body(pet) (4)
  .retrieve()
  .toBodilessEntity(); (5)
1Pet ドメインオブジェクトを作成する
2POST リクエストと接続先の URL を設定します
3Content-Type ヘッダーを application/json に設定します
4 リクエストボディとして pet を使用します
5 レスポンスを本文のないレスポンスエンティティに変換します。
val pet: Pet = ... (1)
val response = restClient.post() (2)
  .uri("https://petclinic.example.com/pets/new") (2)
  .contentType(APPLICATION_JSON) (3)
  .body(pet) (4)
  .retrieve()
  .toBodilessEntity() (5)
1Pet ドメインオブジェクトを作成する
2POST リクエストと接続先の URL を設定します
3Content-Type ヘッダーを application/json に設定します
4 リクエストボディとして pet を使用します
5 レスポンスを本文のないレスポンスエンティティに変換します。

エラー処理

デフォルトでは、RestClient は 4xx または 5xx ステータスコードを含むレスポンスを取得するときに RestClientException のサブクラスをスローします。この動作は onStatus を使用してオーバーライドできます。

  • Java

  • Kotlin

String result = restClient.get() (1)
  .uri("https://example.com/this-url-does-not-exist") (1)
  .retrieve()
  .onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { (2)
      throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); (3)
  })
  .body(String.class);
1404 ステータスコードを返す URL の GET リクエストを作成する
2 すべての 4xx ステータスコードのステータスハンドラーをセットアップする
3 カスタム例外をスローする
val result = restClient.get() (1)
  .uri("https://example.com/this-url-does-not-exist") (1)
  .retrieve()
  .onStatus(HttpStatusCode::is4xxClientError) { _, response -> (2)
    throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) } (3)
  .body<String>()
1404 ステータスコードを返す URL の GET リクエストを作成する
2 すべての 4xx ステータスコードのステータスハンドラーをセットアップする
3 カスタム例外をスローする

交換

より高度なシナリオの場合、RestClient は、retrieve() の代わりに使用できる exchange() メソッドを介して、基礎となる HTTP リクエストおよびレスポンスへのアクセスを提供します。exchange() を使用する場合、ステータスハンドラーは適用されません。これは、交換関数によって完全なレスポンスへのアクセスがすでに提供されており、必要なエラー処理を実行できるためです。

  • Java

  • Kotlin

Pet result = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id)
  .accept(APPLICATION_JSON)
  .exchange((request, response) -> { (1)
    if (response.getStatusCode().is4xxClientError()) { (2)
      throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); (2)
    }
    else {
      Pet pet = convertResponse(response); (3)
      return pet;
    }
  });
1exchange はリクエストとレスポンスを提供します
2 レスポンスに 4xx ステータスコードがある場合に例外をスローする
3 レスポンスを Pet ドメインオブジェクトに変換する
val result = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id)
  .accept(MediaType.APPLICATION_JSON)
  .exchange { request, response -> (1)
    if (response.getStatusCode().is4xxClientError()) { (2)
      throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) (2)
    } else {
      val pet: Pet = convertResponse(response) (3)
      pet
    }
  }
1exchange はリクエストとレスポンスを提供します
2 レスポンスに 4xx ステータスコードがある場合に例外をスローする
3 レスポンスを Pet ドメインオブジェクトに変換する

HTTP メッセージ変換

Jackson JSON ビュー

オブジェクトプロパティのサブセットのみを直列化するには、次の例に示すように、Jackson JSON ビュー (英語) を指定できます。

MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);

ResponseEntity<Void> response = restClient.post() // or RestTemplate.postForEntity
  .contentType(APPLICATION_JSON)
  .body(value)
  .retrieve()
  .toBodilessEntity();

マルチパート

マルチパートデータを送信するには、値がパーツコンテンツ用の Object、ファイルパーツ用の Resource、ヘッダー付きパーツコンテンツ用の HttpEntity である MultiValueMap<String, Object> を提供する必要があります。例:

MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();

parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));

// send using RestClient.post or RestTemplate.postForEntity

ほとんどの場合、パーツごとに Content-Type を指定する必要はありません。コンテンツ型は、直列化するために選択された HttpMessageConverter に基づいて、または Resource の場合はファイル拡張子に基づいて自動的に決定されます。必要に応じて、MediaType に HttpEntity ラッパーを明示的に提供できます。

MultiValueMap の準備ができたら、RestClient.post().body(parts) (または RestTemplate.postForObject) を使用して、それを POST リクエストの本文として使用できます。

MultiValueMap に少なくとも 1 つの非 String 値が含まれている場合、Content-Type は FormHttpMessageConverter によって multipart/form-data に設定されます。MultiValueMap に String 値がある場合、Content-Type はデフォルトで application/x-www-form-urlencoded になります。必要に応じて、Content-Type を明示的に設定することもできます。

クライアントリクエストファクトリ

HTTP リクエストを実行するために、RestClient はクライアント HTTP ライブラリを使用します。これらのライブラリは、ClientRequestFactory インターフェースを介して適応されます。さまざまな実装が利用可能です。

  • Java の HttpClientJdkClientHttpRequestFactory 

  • HttpComponentsClientHttpRequestFactory は Apache HTTP コンポーネント HttpClient と一緒に使用します

  • Jetty の HttpClientJettyClientHttpRequestFactory 

  • ReactorNettyClientRequestFactory Reactor 用 Netty の HttpClient

  • 単純なデフォルトとしての SimpleClientHttpRequestFactory 

RestClient がビルドされたときにリクエストファクトリが指定されていない場合、クラスパスで使用可能な場合は Apache または Jetty HttpClient が使用されます。それ以外の場合、java.net.http モジュールがロードされると、Java の HttpClient が使用されます。最終的には、単純なデフォルトが使用されます。

SimpleClientHttpRequestFactory は、エラーを表すレスポンスのステータス (たとえば、401) にアクセスするときに例外を発生させる可能性があることに注意してください。これが課題になる場合は、代替のリクエストファクトリのいずれかを使用してください。

WebClient

WebClient は、HTTP リクエストを実行するためのノンブロッキングのリアクティブクライアントです。これは 5.0 で導入され、同期、非同期、ストリーミングのシナリオをサポートする RestTemplate の代替手段を提供します。

WebClient は以下をサポートします。

  • ノンブロッキング I/O

  • Reactive Streams バックプレッシャー

  • 少ないハードウェアリソースで高い同時実行性を実現

  • Java 8 ラムダを利用する関数型スタイルの流れるような API

  • 同期および非同期の相互作用

  • サーバーへのストリーミングまたはサーバーからのストリーミングダウン

詳細については、WebClient を参照してください。

RestTemplate

RestTemplate は、HTTP クライアントライブラリを介した高レベルの API を、従来の Spring テンプレートクラスの形式で提供します。これは、次のオーバーロードされたメソッドのグループを公開します。

RestClient は、同期 HTTP アクセス用のより最新の API を提供します。非同期およびストリーミングのシナリオの場合は、リアクティブ WebClient を検討してください。
表 1: RestTemplate メソッド
メソッドグループ 説明

getForObject

GET を介して表現を取得します。

getForEntity

GET を使用して ResponseEntity (つまり、ステータス、ヘッダー、本文)を取得します。

headForHeaders

HEAD を使用して、リソースのすべてのヘッダーを取得します。

postForLocation

POST を使用して新しいリソースを作成し、レスポンスから Location ヘッダーを返します。

postForObject

POST を使用して新しいリソースを作成し、レスポンスから表現を返します。

postForEntity

POST を使用して新しいリソースを作成し、レスポンスから表現を返します。

put

PUT を使用してリソースを作成または更新します。

patchForObject

PATCH を使用してリソースを更新し、レスポンスから表現を返します。JDK HttpURLConnection は PATCH をサポートしていませんが、Apache HttpComponents などはサポートしていることに注意してください。

delete

DELETE を使用して、指定された URI のリソースを削除します。

optionsForAllow

ALLOW を使用して、リソースに許可された HTTP メソッドを取得します。

exchange

必要に応じて柔軟性を高める、前述のメソッドのより一般化された(そしてあまり独自ではない)バージョン。RequestEntity (HTTP メソッド、URL、ヘッダー、本文を入力として含む)を受け入れ、ResponseEntity を返します。

これらのメソッドでは、Class の代わりに ParameterizedTypeReference を使用して、ジェネリクスでレスポンス型を指定できます。

execute

コールバックインターフェースを介したリクエストの準備とレスポンスの抽出を完全に制御して、リクエストを実行する最も一般的な方法。

初期化

RestTemplate は、RestClient と同じ HTTP ライブラリ抽象化を使用します。デフォルトでは SimpleClientHttpRequestFactory が使用されますが、これはコンストラクターを介して変更できます。クライアントリクエストファクトリを参照してください。

RestTemplate は、メトリクスとトレースを生成するために、可観測性のためにインストルメント化できます。RestTemplate 可観測性のサポートセクションを参照してください。

本文

RestTemplate メソッドに渡されるオブジェクトと RestTemplate メソッドから返されるオブジェクトは、HttpMessageConverter を使用して HTTP メッセージに変換されます。HTTP メッセージ変換を参照してください。

RestTemplate から RestClient への移行

次の表は、RestTemplate メソッドに相当する RestClient を示しています。後者から前者への移行にも使用できます。

表 2: RestTemplate のメソッドと RestClient の対応
RestTemplate メソッド RestClient 同等

getForObject(String, Class, Object…​)

get() .uri(String, Object…​) .retrieve() .body(Class)

getForObject(String, Class, Map)

get() .uri(String, Map) .retrieve() .body(Class)

getForObject(URI, Class)

get() .uri(URI) .retrieve() .body(Class)

getForEntity(String, Class, Object…​)

get() .uri(String, Object…​) .retrieve() .toEntity(Class)

getForEntity(String, Class, Map)

get() .uri(String, Map) .retrieve() .toEntity(Class)

getForEntity(URI, Class)

get() .uri(URI) .retrieve() .toEntity(Class)

headForHeaders(String, Object…​)

head() .uri(String, Object…​) .retrieve() .toBodilessEntity() .getHeaders()

headForHeaders(String, Map)

head() .uri(String, Map) .retrieve() .toBodilessEntity() .getHeaders()

headForHeaders(URI)

head() .uri(URI) .retrieve() .toBodilessEntity() .getHeaders()

postForLocation(String, Object, Object…​)

post() .uri(String, Object…​) .body(Object).retrieve() .toBodilessEntity() .getLocation()

postForLocation(String, Object, Map)

post() .uri(String, Map) .body(Object) .retrieve() .toBodilessEntity() .getLocation()

postForLocation(URI, Object)

post() .uri(URI) .body(Object) .retrieve() .toBodilessEntity() .getLocation()

postForObject(String, Object, Class, Object…​)

post() .uri(String, Object…​) .body(Object) .retrieve() .body(Class)

postForObject(String, Object, Class, Map)

post() .uri(String, Map) .body(Object) .retrieve() .body(Class)

postForObject(URI, Object, Class)

post() .uri(URI) .body(Object) .retrieve() .body(Class)

postForEntity(String, Object, Class, Object…​)

post() .uri(String, Object…​) .body(Object) .retrieve() .toEntity(Class)

postForEntity(String, Object, Class, Map)

post() .uri(String, Map) .body(Object) .retrieve() .toEntity(Class)

postForEntity(URI, Object, Class)

post() .uri(URI) .body(Object) .retrieve() .toEntity(Class)

put(String, Object, Object…​)

put() .uri(String, Object…​) .body(Object) .retrieve() .toBodilessEntity()

put(String, Object, Map)

put() .uri(String, Map) .body(Object) .retrieve() .toBodilessEntity()

put(URI, Object)

put() .uri(URI) .body(Object) .retrieve() .toBodilessEntity()

patchForObject(String, Object, Class, Object…​)

patch() .uri(String, Object…​) .body(Object) .retrieve() .body(Class)

patchForObject(String, Object, Class, Map)

patch() .uri(String, Map) .body(Object) .retrieve() .body(Class)

patchForObject(URI, Object, Class)

patch() .uri(URI) .body(Object) .retrieve() .body(Class)

delete(String, Object…​)

delete() .uri(String, Object…​) .retrieve() .toBodilessEntity()

delete(String, Map)

delete() .uri(String, Map) .retrieve() .toBodilessEntity()

delete(URI)

delete() .uri(URI) .retrieve() .toBodilessEntity()

optionsForAllow(String, Object…​)

options() .uri(String, Object…​) .retrieve() .toBodilessEntity() .getAllow()

optionsForAllow(String, Map)

options() .uri(String, Map) .retrieve() .toBodilessEntity() .getAllow()

optionsForAllow(URI)

options() .uri(URI) .retrieve() .toBodilessEntity() .getAllow()

exchange(String, HttpMethod, HttpEntity, Class, Object…​)

method(HttpMethod) .uri(String, Object…​) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(String, HttpMethod, HttpEntity, Class, Map)

method(HttpMethod) .uri(String, Map) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(URI, HttpMethod, HttpEntity, Class)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(String, HttpMethod, HttpEntity, ParameterizedTypeReference, Object…​)

method(HttpMethod) .uri(String, Object…​) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(String, HttpMethod, HttpEntity, ParameterizedTypeReference, Map)

method(HttpMethod) .uri(String, Map) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(URI, HttpMethod, HttpEntity, ParameterizedTypeReference)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(RequestEntity, Class)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [2]

exchange(RequestEntity, ParameterizedTypeReference)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [2]

execute(String, HttpMethod, RequestCallback, ResponseExtractor, Object…​)

method(HttpMethod) .uri(String, Object…​) .exchange(ExchangeFunction)

execute(String, HttpMethod, RequestCallback, ResponseExtractor, Map)

method(HttpMethod) .uri(String, Map) .exchange(ExchangeFunction)

execute(URI, HttpMethod, RequestCallback, ResponseExtractor)

method(HttpMethod) .uri(URI) .exchange(ExchangeFunction)

HTTP インターフェース

Spring Framework を使用すると、@HttpExchange メソッドを使用して HTTP サービスを Java インターフェースとして定義できます。このようなインターフェースを HttpServiceProxyFactory に渡して、RestClient や WebClient などの HTTP クライアント経由でリクエストを実行するプロキシを作成できます。サーバーリクエスト処理のために @Controller からインターフェースを実装することもできます。

まず、@HttpExchange メソッドを使用してインターフェースを作成します。

interface RepositoryService {

	@GetExchange("/repos/{owner}/{repo}")
	Repository getRepository(@PathVariable String owner, @PathVariable String repo);

	// more HTTP exchange methods...

}

これで、メソッドが呼び出されたときにリクエストを実行するプロキシを作成できるようになりました。

RestClient の場合:

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);

WebClient の場合:

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);

RestTemplate の場合:

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 は、すべてのメソッドに適用される型レベルでサポートされています。

@HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json")
interface RepositoryService {

	@GetExchange
	Repository getRepository(@PathVariable String owner, @PathVariable String repo);

	@PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
	void updateRepository(@PathVariable String owner, @PathVariable String repo,
			@RequestParam String name, @RequestParam String description, @RequestParam String homepage);

}

メソッドパラメーター

アノテーション付きの HTTP 交換メソッドは、次のメソッドパラメーターを使用して柔軟なメソッドシグネチャーをサポートします。

メソッド引数 説明

URI

アノテーションの url 属性をオーバーライドして、リクエストの URL を動的に設定します。

UriBuilderFactory

URI テンプレートと URI 変数を展開するための UriBuilderFactory を提供します。実際には、基礎となるクライアントの UriBuilderFactory (およびそのベース URL) を置き換えます。

HttpMethod

アノテーションの method 属性をオーバーライドして、リクエストの HTTP メソッドを動的に設定します

@RequestHeader

リクエストヘッダーまたは複数のヘッダーを追加します。引数は、複数のヘッダーを持つ Map<String, ?> または MultiValueMap<String, ?>、値の Collection<?>、または個別の値です。文字列以外の値では、型変換がサポートされています。これにより、アノテーションの headers 属性がオーバーライドされます。

@PathVariable

リクエスト URL にプレースホルダーを展開するための変数を追加します。引数は、複数の変数を持つ Map<String, ?>、または個別の値の場合があります。文字列以外の値では型変換がサポートされています。

@RequestAttribute

リクエスト属性として追加する Object を指定します。RestClient と WebClient でのみサポートされます。

@RequestBody

リクエストの本文を、直列化するオブジェクトとして、または Reactive Streams Publisher (MonoFlux など)、構成済みの ReactiveAdapterRegistry でサポートされるその他の非同期型として提供します。

@RequestParam

リクエストパラメーターまたは複数のパラメーターを追加します。引数は、複数のパラメーターを持つ Map<String, ?> または MultiValueMap<String, ?>、値の Collection<?>、または個々の値の場合があります。文字列以外の値の型変換がサポートされています。

"content-type" が "application/x-www-form-urlencoded" に設定されている場合、リクエストパラメーターはリクエスト本文にエンコードされます。それ以外の場合は、URL クエリパラメーターとして追加されます。

@RequestPart

リクエスト部分を追加します。リクエスト部分は、文字列 (フォームフィールド)、Resource (ファイル部分)、オブジェクト (JSON などの形式でエンコードされるエンティティ)、HttpEntity (部分コンテンツとヘッダー)、上記のいずれかの Spring Part、または Reactive Streams Publisher になります。

MultipartFile

MultipartFile からのリクエストパーツを追加します。これは通常、アップロードされたファイルを表す Spring MVC コントローラーで使用されます。

@CookieValue

1 つまたは複数の Cookie を追加します。引数は、複数の Cookie を持つ Map<String, ?> または MultiValueMap<String, ?>、値の Collection<?>、または個々の値です。文字列以外の値の型変換がサポートされています。

required 属性 (パラメーターアノテーションで使用可能な場合) が false に設定されていない限り、またはパラメーターが MethodParameter#isOptional (Javadoc) によって決定されたオプションとしてマークされていない限り、メソッドパラメーターを null にすることはできません。

戻り値

サポートされる戻り値は、基礎となるクライアントによって異なります。

RestClient や RestTemplate などの HttpExchangeAdapter に適応したクライアントは、同期戻り値をサポートします。

メソッドの戻り値 説明

void

与えられたリクエストを実行します。

HttpHeaders

指定されたリクエストを実行し、レスポンスヘッダーを返します。

<T>

指定されたリクエストを実行し、レスポンスの内容を宣言された戻り値の型にデコードします。

ResponseEntity<Void>

指定されたリクエストを実行し、ステータスとヘッダーを含む ResponseEntity を返します。

ResponseEntity<T>

指定されたリクエストを実行し、レスポンスコンテンツを宣言された戻り値の型にデコードし、ステータス、ヘッダー、デコードされた本文を含む ResponseEntity を返します。

WebClient などの ReactorHttpExchangeAdapter に適応したクライアントは、上記のすべてとリアクティブなバリアントをサポートします。以下の表は Reactor 型を示していますが、ReactiveAdapterRegistry でサポートされている他のリアクティブ型も使用できます。

メソッドの戻り値 説明

Mono<Void>

指定されたリクエストを実行し、レスポンスコンテンツがある場合はそれを解放します。

Mono<HttpHeaders>

指定されたリクエストを実行し、レスポンスコンテンツがある場合はそれを解放して、レスポンスヘッダーを返します。

Mono<T>

指定されたリクエストを実行し、レスポンスの内容を宣言された戻り値の型にデコードします。

Flux<T>

指定されたリクエストを実行し、レスポンスコンテンツを宣言された要素型のストリームにデコードします。

Mono<ResponseEntity<Void>>

指定されたリクエストを実行し、レスポンスコンテンツがある場合はそれを解放して、ステータスとヘッダーを含む ResponseEntity を返します。

Mono<ResponseEntity<T>>

指定されたリクエストを実行し、レスポンスコンテンツを宣言された戻り値の型にデコードし、ステータス、ヘッダー、デコードされた本文を含む ResponseEntity を返します。

Mono<ResponseEntity<Flux<T>>

指定されたリクエストを実行し、レスポンスコンテンツを宣言された要素型のストリームにデコードし、ステータス、ヘッダー、デコードされたレスポンス本文ストリームを含む ResponseEntity を返します。

デフォルトでは、ReactorHttpExchangeAdapter による同期戻り値のタイムアウトは、基礎となる HTTP クライアントの構成方法によって異なります。アダプターレベルで blockTimeout 値を設定することもできますが、下位レベルで動作し、より詳細な制御を提供する、基盤となる HTTP クライアントのタイムアウト設定に依存することをお勧めします。

エラー処理

エラーレスポンス処理をカスタマイズするには、基礎となる HTTP クライアントを構成する必要があります。

RestClient の場合:

デフォルトでは、RestClient は 4xx および 5xx HTTP ステータスコードに対して RestClientException を生成します。これをカスタマイズするには、クライアントを通じて実行されるすべてのレスポンスに適用されるレスポンスステータスハンドラーを登録します。

RestClient restClient = RestClient.builder()
		.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
		.build();

RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();

エラーステータスコードの抑制などの詳細とオプションについては、RestClient.Builder の defaultStatusHandler の Javadoc を参照してください。

WebClient の場合:

デフォルトでは、WebClient は 4xx および 5xx HTTP ステータスコードに対して WebClientResponseException を生成します。これをカスタマイズするには、クライアントを通じて実行されるすべてのレスポンスに適用されるレスポンスステータスハンドラーを登録します。

WebClient webClient = WebClient.builder()
		.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
		.build();

WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(adapter).build();

エラーステータスコードの抑制などの詳細とオプションについては、WebClient.Builder の defaultStatusHandler の Javadoc を参照してください。

RestTemplate の場合:

デフォルトでは、RestTemplate は 4xx および 5xx HTTP ステータスコードに対して RestClientException を生成します。これをカスタマイズするには、クライアントを通じて実行されるすべてのレスポンスに適用されるエラーハンドラーを登録します。

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(myErrorHandler);

RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();

詳細とオプションについては、RestTemplate および ResponseErrorHandler 階層の setErrorHandler の Javadoc を参照してください。


1HttpEntity ヘッダーと本体は、headers(Consumer<HttpHeaders>) および body(Object) 経由で RestClient に提供される必要があります。
2RequestEntity メソッド、URI、ヘッダー、本文は、method(HttpMethod)uri(URI)headers(Consumer<HttpHeaders>)body(Object) 経由で RestClient に提供する必要があります。