spring.svg

【Spring Boot】RestTemplateによるAPI呼び出し

SpringBoot

はじめに

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には以下の引数を設定します。

引数説明
1String送信先 URL
2HttpMethodリクエストメソッド
3HttpEntity<T>リクエスト情報
4Class<T>レスポンスボディの型

第三引数には、リクエストヘッダーやリクエストボディ等の情報を設定します。 上記では不要のためnullとしています。

レスポンス情報は、ResponseEntity<?>として受け取ります。 ジェネリクスの型には、レスポンスボディの型を設定します。 つまり、exchangeの第四引数と同じものを設定することになります。 上記ではStringとしているため、レスポンスボディを取得するgetBody()の戻り値はStringとなります。

レスポンスボディの取得

レスポンスボディは、Stringの他に、データフォーマットに合わせたオブジェクトとして取得することができます。

Sample.java
@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に置き換えたものが以下になります。

1件取得
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 系のレスポンスを受け取った際に、それぞれHttpClientErrorExceptoinHttpServerErrorExceptionをスローします。

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