概要
RESTなAPIにアクセスするのはRestTemplateではなくWebClientが今後推奨となるため、WebClientの概要についてまとめた。
WebClientを使用するための準備と、どんなメソッドがあるのかを紹介している。
前提
今後動作確認を行う際には、以前の記事で作成したREST APIアプリにリクエストを行ってレスポンスを取得する。
※今回のMavenプロジェクトの作成についても、以下をベースとしている
概要 これから数回にかけてREST APIについて学んだことを載せていく。 今回はREST APIの仕組みとプロジェクト作成方法について紹介する。 尚、RESTとは何かということについては取り扱わない。 仕組み[…]
WebClient
WebClientは、Spring Framework5以降で導入された非同期・リアクティブなHTTPクライアントとなる。
REST APIや外部サービスとHTTP経由で通信する際に使用し、GET/POST/PUT/DELETE などのHTTPメソッドを柔軟に扱える。
※SpringMVCでは一律同期的に処理を行うため、以降の記事では非同期の処理については扱わない
基本的な使い方
WebClientでは、以下のようにメソッドチェーンを使用して柔軟にAPI通信を行う。(※GET通信の例)
.uri(URI情報)
.retrieve()
.bodyToMono(取得したいレスポンスの型)
.block();
GET通信を行うメソッド。(「webClient」は、WebClientのインスタンス)
この段階ではリクエストはまだ実施せず、内部型のWebClient.RequestHeadersUriSpecオブジェクトを返却する。
リクエストの URI を設定する。
WebClient.RequestHeadersSpec<?> を返し、ヘッダー設定や送信メソッドが利用可能になる。
リクエストを送信し、レスポンスを扱うWebClient.ResponseSpecを返却する。
レスポンスボディを非同期で扱う Mono<取得したい型> を返す。
※上記のメソッドは、レスポンスボディのみ(ステータスやヘッダーは含まない)を扱う
非同期処理が完了するまで待機し、同期的な戻り値として取得する。
Spring MVCでは、基本的にこのメソッドで同期処理に変換する。
基本的なメソッド
WebClientは内部型オブジェクトとMonoオブジェクトを使用してAPI通信を行う。
以下にWebClientにてメソッドチェーンで使用する基本的なメソッドを紹介する。
メソッド | 説明 |
---|---|
WebClient.get() | GET通信を行う |
WebClient.post() | POST通信を行う |
WebClient.put() | PUT通信を行う |
WebClient.delete() | DELETE通信を行う |
UriSpec.uri(URI情報) | URI情報を設定する |
RequestBodySpec.bodyValue(リクエストボディ) | POSTやPUT通信に使用するリクエストボディを設定する |
RequestBodySpec.contentType(コンテンツタイプ) | Content-Typeヘッダーを設定する |
RequestHeadersSpec.headers(ヘッダー情報) | リクエストのヘッダー情報を設定 |
RequestHeadersSpec.retrieve() | リクエスト送信を行い、ResponseSpecを取得する |
RequestHeadersSpec.exchangeToMono() | リクエスト送信を行い、ClientResponseを変換してMono<T>を取得する ※ClientResponseはヘッダー/ステータス/ボディにアクセス可能なオブジェクト |
ResponseSpec.bodyToMono(レスポンス型) | リクエスト送信を行い、Mono<T>を取得する |
Mono<T>.block() | 同期的にT型のレスポンスを取得する |
事前準備
WebClientを使用するための事前準備を行う。
必要ライブラリ
WebClientまわりの機能を利用するため、必要な資材をpom.xmlに追加する。
pom.xml
<dependencies>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- Spring Web MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.30</version>
</dependency>
<!-- Spring WebFlux -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<version>5.3.30</version>
</dependency>
<!-- Project Reactor Core -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.4.34</version>
</dependency>
<!-- Project Reactor Netty -->
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
<version>1.0.39</version>
</dependency>
<!-- SLF4J API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<!-- Logback Classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
<!-- Jackson Datatype JSR310 for Java Time API -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.15.2</version>
</dependency>
</dependencies>
WebClientを使用するためには以下の資材が必要となる。
・Project Reactor Core: Monoオブジェクトなどの機能
・Project Reactor Netty: 非同期HTTP通信の機能
Bean定義
WebClientをDIコンテナから取得するため、Bean定義を行う。
簡潔に記述できるため、Javaベースで作成する。
WebClientConfig.java
package com.example.webclient_prototype.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
/**
* WebClientのBean定義
*/
@Configuration
public class WebClientConfig {
@Bean
public HttpClient httpClient() {
return HttpClient.create();
}
@Bean
public ReactorClientHttpConnector reactorClientHttpConnector(HttpClient httpClient) {
return new ReactorClientHttpConnector(httpClient);
}
@Bean
public WebClient webClient(ReactorClientHttpConnector reactorClientHttpConnector) {
return WebClient.builder()
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE + ", " + MediaType.APPLICATION_PROBLEM_JSON_VALUE)
.clientConnector(reactorClientHttpConnector)
.build();
}
}
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE + “, ” + MediaType.APPLICATION_PROBLEM_JSON_VALUE)
WebClientを使用して行うすべてのHTTPリクエストに、共通のHTTPヘッダーを設定している。
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!-- コンポーネントスキャン -->
<context:component-scan base-package="com.example.webclient_prototype.biz" />
<!-- WebClientのBean定義 -->
<bean class="com.example.webclient_prototype.config.WebClientConfig"/>
</beans>
<bean class=”com.example.webclient_prototype.config.WebClientConfig”/>
定義したJavaベースのBean定義ファイルをDIコンテナに登録する。
※コンポーネントスキャン対象のパッケージ配下に格納していれば不要
APIアクセスクラス
WebClientのDIを行い、APIにアクセスするメソッドを今後追加していく。
WebApiClient.java
package com.example.webclient_prototype.biz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
/**
* WebClientを使用したAPI疎通クラス
*/
@Component
public class WebApiClient {
@Autowired
private WebClient webClient;
}
リソースクラス
REST APIアプリから返却されるレスポンスを、リソースクラスにマッピングするため用意する。
Resource.java
package com.example.webclient_prototype.resource;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* リソースクラス
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Resource {
/** ID */
private String id;
/** 名前 */
private String name;
/** とある日付 */
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate hogeDate;
}
動作確認用クラス
WebClientの動作を簡易的に確認するため、エントリーポイントとなるクラスを用意する。
Main.java
package com.example.webclient_prototype.executor;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.webclient_prototype.biz.WebApiClient;
public class Main {
public static void main(String[] args) {
try (var context = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml")) {
// DIコンテナから取得
var client = context.getBean(WebApiClient.class);
}
}
}
まとめ
☑ RestTemplateは今後機能追加がないため、WebClientの使用が推奨される
☑ WebClientはメソッドチェーンで柔軟なAPI通信を実装できる
☑ SpringMVC環境では、 WebClientを同期的に使用する