【Spring Boot】RestTemplateによるAPI呼び出し
はじめに
Spring Boot で外部の API に接続するには、RestTemplate
を使用します。
この記事では以下の GET、POST の API へのリクエストを例に、RestTemplate
の使用方法について説明します。
RestTemplate
には、リクエストを送信するためのメソッドがいくつか用意されているため、それぞれ簡単に説明していきます。
- 1 件取得Request
GET http://hoge.com/api/sample/1
Response{ "id": 1, "name": "Tanaka Taro", "age": 16 }
- 検索Request
GET http://hoge.com/api/sample?name=xxx&age=xx
Response[ { "id": 1, "name": "Tanaka Taro", "age": 16 }, { "id": 3, "name": "Tanaka Hanako", "age": 16 } ]
- 登録Reqeust
POST http://hoge.com/api/sample { "id": 10, "name": "Suzuki Ichiro", "age": 11 }
exchange
リクエストの送信
String url = "http://hoge.com/api/sample/1";
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
//結果の取得
HttpStatus status = response.getStatusCode();
String body = response.getBody();
RestTemplate
の中で汎用的に利用できるのがexchange
です。
exchange
には以下の引数を設定します。
引数 | 型 | 説明 |
---|---|---|
1 | String | 送信先 URL |
2 | HttpMethod | リクエストメソッド |
3 | HttpEntity<T> | リクエスト情報 |
4 | Class<T> | レスポンスボディの型 |
第三引数には、リクエストヘッダーやリクエストボディ等の情報を設定します。
上記では不要のためnull
としています。
レスポンス情報は、ResponseEntity<?>
として受け取ります。
ジェネリクスの型には、レスポンスボディの型を設定します。
つまり、exchange
の第四引数と同じものを設定することになります。
上記ではString
としているため、レスポンスボディを取得するgetBody()
の戻り値はString
となります。
レスポンスボディの取得
レスポンスボディは、String
の他に、データフォーマットに合わせたオブジェクトとして取得することができます。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Sample {
private long id;
private String name;
private int age;
}
ResponseEntity<Sample> response = restTemplate.exchange(url, HttpMethod.GET, null, Sample.class);
Sample body = response.getBody();
また、一旦String
で受け取り、後に JSON からオブジェクトに変換することもできます。
String strBody = response.getBody();
ObjectMapper mapper = new ObjectMapper();
TypeReference<Map<String, Object>> type = new TypeReference<Map<String, Object>>(){};
Map<String, Object> body = mapper.readValue(strBody, type);
クエリパラメータ―の設定
クエリパラメータ―は、URL を{}
を用いてテンプレート化することで設定できます。
String url = "http://hoge.com/api/sample?name={name}&age={age}";
String name = "Tanaka"
String age = "16";
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, null, String.class, name, age);
//結果の取得
String strBody = response.getBody();
ObjectMapper mapper = new ObjectMapper();
TypeReference<List<Map<String, Object>>> type = new TypeReference<List<Map<String, Object>>>(){};
List<Map<String, Object>> body = mapper.readValue(strBody, type);
exchange
の第五引数以降は可変長引数となっており、{}
の順に指定した値が URL エンコードされた状態で設定されます。
明示的に指定したい場合は、以下のようにパラメータ―用のMap
を作成します。
String url = "http://hoge.com/api/sample?name={name}&age={age}";
Map<String, String> params = new HashMap<>();
params.put("name", "Tanaka");
params.put("age", "16");
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, null, String.class, params);
リクエスト情報の設定
登録用の API に JSON を送信することを考えます。
やることとしては、①Content-Type: application/json
を設定、② リクエストボディに JSON を設定、の 2 つです。
まず ① を設定するために、リクエストヘッダーを作成します。
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
その他リクエストヘッダーの設定が必要な場合は、以下のように設定してください。
headers.add("apikey", "xxxxxxxxxxxxxxxxxxxxxxxxxxx");
次に ② のため、リクエストボディに設定するオブジェクトを作成します。
Sample sample = new Sample(10, "Suzuki Ichiro", 11);
最後に ① と ② を合わせたリクエスト情報を作成し、リクエストを送信します。
HttpEntity<Sample> entity = new HttpEntity<>(sample, headers);
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
HttpEntity<?>
のジェネリクスには、リクエストボディに設定するオブジェクトの型を設定します。
作成したHttpEntity<?>
は、exchange
の第三引数に設定します。
RequestEntity
上記と同じくexchange
を使用しますが、RequestEntity
を引数として指定します。
各 API への接続をRequestEntity
に置き換えたものが以下になります。
String url = "http://hoge.com/api/sample/1";
//リクエスト情報の作成
RequestEntity<?> request = RequestEntity.get(url).build();
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(request, String.class);
String url = "http://hoge.com/api/sample?name={name}&age={age}";
String name = "Tanaka";
String age = "16";
//リクエスト情報の作成
RequestEntity<?> request = RequestEntity.get(url, name, age).build();
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(request, String.class);
String url = "http://hoge.com/api/sample";
//リクエスト情報の作成
Sample sample = new Sample(10, "Suzuki Ichiro", 11);
RequestEntity<Sample> request = RequestEntity.post(url)
.contentType(MediaType.APPLICATION_JSON)
.body(sample);
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(request, String.class);
RequestEntity
には、HTTP メソッドに応じたメソッド(get()
など)が用意されており、引数に URL とテンプレートパラメータ―を設定します。
リクエストボディへの設定はbody()
で行い、contentType()
によってその種類を設定します。
リクエストヘッダーを設定する場合は、HttpHeaders
を作成し、headers()
で設定します。
RequestEntity.post(url).headers(headers).body(sample);
RequestEntity
オブジェクトは、get()
ではbuild()
で生成され、post()
ではbody()
で生成されます。
RequestEntity
のジェネリクスの型は、リクエストボディに設定したオブジェクトの型を設定します。
get()
ではリクエストボディを設定できないようになっているため、?
としています。
参考:PUT は POST と、DELETE は GET と同じ仕様で
RequestEntity
を生成します。
getForObject, postForObject
getForObject
は、リクエストの結果としてResponseEntity<?>
ではなく、レスポンスボディを直接取得します。
String url = "http://hoge.com/api/sample/1";
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
String body = restTemplate.getForObject(url, String.class);
postForObject
も同様です。
String url = "http://hoge.com/api/sample";
//ヘッダー情報作成
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//リクエスト情報作成
Sample sample = new Sample(10, "Suzuki Ichiro", 11);
HttpEntity<Sample> entity = new HttpEntity<>(sample, headers);
//リクエストの送信
RestTemplate restTemplate = new RestTemplate();
String body = restTemplate.postForObject(url, entity, String.class);
参考: 同様の PUT、DELETE のメソッドはありません。
エラーハンドリング
RestTemplate
では、4xx 系、5xx 系のレスポンスを受け取った際に、それぞれHttpClientErrorExceptoin
、HttpServerErrorException
をスローします。
try {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
} catch (HttpClientErrorException e) {
//4xx系のエラー
int status = e.getRawStatusCode();
String body = e.getResponseBodyAsString();
} catch (HttpServerErrorException e) {
//5xx系のエラー
int status = e.getRawStatusCode();
String body = e.getResponseBodyAsString();
}