Javaで作るREST API Client（JerseyClient/RestTemplate）

# やりたいこと
JakartaEEのJAX-RS（Jersey）とSpringBoot両方でREST Clientを作成したい。

# 前提
JakartaEEでは、JAX-RS（JerseyClient（4.0.0-M1））、SpringBoot（3.4.1）ではRestTemplateを使用してREST Clientを作成します。

※APIは下記記事で作成したGET/POSTメソッドのAPIを使用します。

https://qiita.com/hiroto_mis/items/b7ac694888277c45de1e

# JAX-RS（Jersey）のJerseyClient
まずは、JakartaEE仕様で作成してみます。
ソースコードは下記Githubリポジトリにコミットしております。

https://github.com/SatoHiroto526/JerseyClient_Sample/tree/master

①pom.xmlの設定
（バージョンは適宜調整してください。）
```
		<!--Jakarta Activation API -->
		<dependency>
			<groupId>jakarta.activation</groupId>
			<artifactId>jakarta.activation-api</artifactId>
			<version>2.1.3</version>
		</dependency>

		<!-- JAX-RS API -->
		<dependency>
			<groupId>jakarta.ws.rs</groupId>
			<artifactId>jakarta.ws.rs-api</artifactId>
			<version>4.0.0</version>
		</dependency>

		<!--Jersey Core Client-->
		<dependency>
			<groupId>org.glassfish.jersey.core</groupId>
			<artifactId>jersey-client</artifactId>
			<version>4.0.0-M1</version>
		</dependency>
		
		<!--Jersey Inject HK2 -->
		<dependency>
			<groupId>org.glassfish.jersey.inject</groupId>
			<artifactId>jersey-hk2</artifactId>
			<version>4.0.0-M1</version>
		</dependency>
```
Jakarta Activation APIとJersey Inject HK2は無くても動作しますが、コンソールに警告メッセージが出るため一応追記します。

②REST Clientを作成
以下がソースコード全体です。
```
package com.example.client;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;

public class SampleClient {
	
	public static void main(String[] args) {
		
		//URI定義
		String getUri = "http://localhost:8080/JerseySample/rest/api/getlist";
		String postUri = "http://localhost:8080/JerseySample/rest/api/getbyid";
		
		//パラメーター定義
		int id = 3;
		
		//GETメソッドのAPIをコール
		get(getUri);
		
		//POSTメソッドのAPIをコール
		post(postUri, id);
	}
	
	//GETメソッドのAPIをコール
	private static void get(String uri) {
		
		//クライアント作成
		Client client = ClientBuilder.newClient();
		
		//URIをターゲットに設定
		WebTarget target = client.target(uri);
		
		//URI、認証情報、リクエストタイプ、メソッドを指定してリクエスト
		Response response = target.register(HttpAuthenticationFeature.basic("test", "test"))
				.request(MediaType.APPLICATION_JSON)
				.get();
		
		//レスポンスを表示
		System.out.println("GET(Response Status):" + response.getStatus());
		System.out.println("GET(Response Body):" + response.readEntity(String.class));
		
		//レスポンスとクライアントをクローズ
		response.close();
		client.close();
		
	}
	
	//POSTメソッドのAPIをコール
	private static void post(String uri, int id) {
		
		//クライアント作成
		Client client = ClientBuilder.newClient();
		
		//URIをターゲットに設定
		WebTarget target = client.target(uri);
		
		//リクエストボディ作成
		String requestBody = "{\"id\":" + id + "}";
		
		//URI、認証情報、リクエストタイプ、メソッド、リクエストボディを指定してリクエスト
		Response response = target.register(HttpAuthenticationFeature.basic("test", "test"))
				.request(MediaType.APPLICATION_JSON)
				.post(Entity.entity(requestBody, MediaType.APPLICATION_JSON));
		
		//レスポンスを表示
		System.out.println("POST(Response Status):" + response.getStatus());
		System.out.println("POST(Response Body):" + response.readEntity(String.class));
		
		//レスポンスとクライアントをクローズ
		response.close();
		client.close();
		
	}

}
```

一個ずつ確認します。
まずはmainメソッドに関して。
```
    public static void main(String[] args) {
		
		//URI定義
		String getUri = "http://localhost:8080/JerseySample/rest/api/getlist";
		String postUri = "http://localhost:8080/JerseySample/rest/api/getbyid";
		
		//パラメーター定義
		int id = 3;
		
		//GETメソッドのAPIをコール
		get(getUri);
		
		//POSTメソッドのAPIをコール
		post(postUri, id);
	}

```
GET/POSTそれぞれのURI定義、POSTメソッドのリクエストボディにセットするパラメーターの定義、GET/POSTそれぞれをコールするメソッドの実行を行っています。

次に、GETをコールするメソッドに関して。
```
	//GETメソッドのAPIをコール
	private static void get(String uri) {
		
		//クライアント作成
		Client client = ClientBuilder.newClient();
		
		//URIをターゲットに設定
		WebTarget target = client.target(uri);
		
		//URI、認証情報、リクエストタイプ、メソッドを指定してリクエスト
		Response response = target.register(HttpAuthenticationFeature.basic("test", "test"))
				.request(MediaType.APPLICATION_JSON)
				.get();
		
		//レスポンスを表示
		System.out.println("GET(Response Status):" + response.getStatus());
		System.out.println("GET(Response Body):" + response.readEntity(String.class));
		
		//レスポンスとクライアントをクローズ
		response.close();
		client.close();
		
	}
```
クライアントの作成、引数で受け取ったURIをクライアントのターゲットにセット、ターゲットに認証情報、形式、メソッドをセットしてAPIをコールします。
また、事後処理としてレスポンスとクライアントをクローズします。

最後にPOSTをコールするメソッドに関して。
```
    //POSTメソッドのAPIをコール
	private static void post(String uri, int id) {
		
		//クライアント作成
		Client client = ClientBuilder.newClient();
		
		//URIをターゲットに設定
		WebTarget target = client.target(uri);
		
		//リクエストボディ作成
		String requestBody = "{\"id\":" + id + "}";
		
		//URI、認証情報、リクエストタイプ、メソッド、リクエストボディを指定してリクエスト
		Response response = target.register(HttpAuthenticationFeature.basic("test", "test"))
				.request(MediaType.APPLICATION_JSON)
				.post(Entity.entity(requestBody, MediaType.APPLICATION_JSON));
		
		//レスポンスを表示
		System.out.println("POST(Response Status):" + response.getStatus());
		System.out.println("POST(Response Body):" + response.readEntity(String.class));
		
		//レスポンスとクライアントをクローズ
		response.close();
		client.close();
		
	}
```
基本的にはGETをコールするメソッドと同じですが、POSTメソッドのAPIはリクエストボディからデータを取得する形式のため、リクエストボディの作成/クライアントへのセットを行っています。

# SpringBootのRestTemplate
次に、SpringBoot仕様で作成してみます。
ソースコードは下記Githubリポジトリにコミットしております。

https://github.com/SatoHiroto526/RestTemplate_Sample/tree/master

①build.gradleの設定
（バージョンは適宜調整してください。）
```
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
```
EclipseでSpringBootスターター・プロジェクトを作成する際にデフォルトで入るAPIのみの構成となっております。

②REST Clientを作成
以下がソースコード全体です。
```
package com.example.demo.client;

import java.util.List;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class SampleClient {

    public static void main(String[] args) {

        // URI定義
        String getUri = "http://localhost:8080/JerseySample/rest/api/getlist";
        String postUri = "http://localhost:8080/JerseySample/rest/api/getbyid";

        // パラメーター定義
        int id = 3;

        // GETメソッドのAPIをコール
        get(getUri);

        // POSTメソッドのAPIをコール
        post(postUri, id);
    }

    // GETメソッドのAPIをコール
    private static void get(String uri) {

        // RestTemplate作成
        RestTemplate restTemplate = new RestTemplateBuilder()
                .basicAuthentication("test", "test")
                .build();

        // ヘッダー設定
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(List.of(MediaType.APPLICATION_JSON));
        HttpEntity<String> entity = new HttpEntity<>(headers);

        // GETリクエストを送信
        ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);

        // レスポンスを表示
        System.out.println("GET(Response Status):" + response.getStatusCodeValue());
        System.out.println("GET(Response Body):" + response.getBody());
    }

    // POSTメソッドのAPIをコール
    private static void post(String uri, int id) {

        // RestTemplate作成
        RestTemplate restTemplate = new RestTemplateBuilder()
                .basicAuthentication("test", "test")
                .build();

        // ヘッダー設定
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setAccept(List.of(MediaType.APPLICATION_JSON));

        // リクエストボディ作成
        String requestBody = "{\"id\":" + id + "}";

        // POSTリクエストを送信
        HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.POST, entity, String.class);

        // レスポンスを表示
        System.out.println("POST(Response Status):" + response.getStatusCodeValue());
        System.out.println("POST(Response Body):" + response.getBody());
    }
}
```

一個ずつ確認します。
（mainメソッドはJerseyClientと全く一緒であるため省略します。）

まずは、GETをコールするメソッドに関して。
```
    // GETメソッドのAPIをコール
    private static void get(String uri) {

        // RestTemplate作成
        RestTemplate restTemplate = new RestTemplateBuilder()
                .basicAuthentication("test", "test")
                .build();

        // ヘッダー設定
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(List.of(MediaType.APPLICATION_JSON));
        HttpEntity<String> entity = new HttpEntity<>(headers);

        // GETリクエストを送信
        ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);

        // レスポンスを表示
        System.out.println("GET(Response Status):" + response.getStatusCodeValue());
        System.out.println("GET(Response Body):" + response.getBody());
    }
```
RestTemplateを作成し、認証情報をセットします。次に、形式をセットしたヘッダー情報を作成し、  HttpEntityにセットします。最後に、RestTemplateにURI、メソッド、HttpEntityをセットしてAPIをコールします。

次に、POSTをコールするメソッドに関して。
```
	// POSTメソッドのAPIをコール
    private static void post(String uri, int id) {

        // RestTemplate作成
        RestTemplate restTemplate = new RestTemplateBuilder()
                .basicAuthentication("test", "test")
                .build();

        // ヘッダー設定
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setAccept(List.of(MediaType.APPLICATION_JSON));

        // リクエストボディ作成
        String requestBody = "{\"id\":" + id + "}";

        // POSTリクエストを送信
        HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.POST, entity, String.class);

        // レスポンスを表示
        System.out.println("POST(Response Status):" + response.getStatusCodeValue());
        System.out.println("POST(Response Body):" + response.getBody());
    }
```
こちらもJersey同様、GETとほとんど変わりませんが、リクエストボディを加える処理だけ追加されています。具体的には、String型のリクエストボディをJSON形式で作成し、HttpEntityのコンストラクタの第一引数にセットしています。

以上、JerseyとRestTemplateで簡単なREST Clientを作成してみました！