🔢

REST通信には、げきつよRestTemplateを使うべし

2021/05/31に公開

RestTemplate

RestTemplateって?

RestTemplateは、REST API(Web API)を呼び出すためのメソッドを提供するクラス。
Spring Frameworkが提供するHTTPクライアント(HttpClientをラップしている)。

まとめると、、、REST通信が簡単にできる便利部品。

DTOからJson形式のリクエストに変換する処理や、Json形式のレスポンスをDTOにバインドする処理をしてくれる。
データ形式はJson以外にXmlやFormなど様々対応していて、カスタマイズも可能!!

DTO => Json

DTO
@Getter // (1)
@Setter // (1)
public class SomeRequestResource {
    private String message; // (2)
}

(1) ライブラリのlombockを使用してGetter, Setterを自動生成
(2) Json変換を後に反映されるフィールド

Json
{
  "messsage": "test message"
}

DTOのフィールド名と値がJson形式に変換される

Json => DTO

Json
{
  "messsage": "test message"
}
DTO
@Getter
@Setter
public class SomeRequestResource {
    private String message; // (1)
}

(1) Jsonの値がバインドされるフィールド

RestTemplateの使い方

「きほん」のき

とりあえずインジェクション

@Service
public class XxxxServiceImpl implements XxxxService {

    @Autowired
    RestTemplate restTemplate;

    // ...

}

今回のメインRestTemplateをインジェクション。このRestTemplateの中にREST通信に使うパーツがいっぱい詰まってる。

GET送信してみる

@Getter
@Setter
public class TestResponseResource {
    private String id;      // (1)
    private String message; // (1)
}

(1) レスポンスをバインドするフィールド

@Service
public class XxxxServiceImpl implements XxxxService {

    @Autowired
    RestTemplate restTemplate;

    public static final String URL = "http://com.example.rest/test";

    public TestResponseResource getTestResponse() {
      // (1)
      return restTemplate.getForObject(URL, TestResponseResource.class);
    }

}

(1) GET送信する。
(1) getForObjectの引数

引数順 説明
1 String 送信先のURL
2 Class<T> 送信先から返却されたResponseBodyをバインドするクラス

POST送信してみる

@Getter
@Setter
public class TestRequestResource {
    private String message;  // (1)
}

(1) 送信する値

@Getter
@Setter
public class TestResponseResource {
    private String id;      // (1)
    private String message; // (1)
}

(1) レスポンスをバインドするフィールド

@Service
public class XxxxServiceImpl implements XxxxService {

    @Autowired
    RestTemplate restTemplate;

    public static final String URL = "http://com.example.rest/test";

    public TestResponseResource getTestResponse() {
      // (1)
      TestRequestResource request = new TestRequestResource();
      request.setMessage("test message");

      // (2)
      return restTemplate.postForObject(URL,request,TestResponseResource.class);
    }

}

(1) 送信データを設定する
(2) POST送信
(2) postForObjectの引数

引数順 説明
1 String 送信先のURL
2 Object 送信する値
3 Class<T> 送信先から返却されたResponseBodyをバインドするクラス

「きほん」のほ

送信URLを動的に変更する

REST通信の場合、URLからResourceのid情報を取得する場合がある。
例) http://com.example.rest/book/1

RestTemplateの場合、複数パターンで実装が可能。

順番にPathParameterつめつめパターン
@Getter
@Setter
public class BookResponseResource {
    private String id;
    private String message;
}
@Service
public class XxxxServiceImpl implements XxxxService {

    @Autowired
    RestTemplate restTemplate;

    // (1)
    public static final String URL = "http://com.example.rest/book/{id}";

    public TestResponseResource getTestResponse() {
      // (2)
      return restTemplate.getForObject(URL, BookResponseResource.class, "1");
    }

}

(1) {id}の箇所にパラメータがバインドされる
(2) 引数の最後にパラメータにバインドしたい文字列を渡す。可変長引数で取るため、複数指定可能。

明示的につめつめパターン
@Getter
@Setter
public class BookResponseResource {
    private String id;
    private String message;
}
@Service
public class XxxxServiceImpl implements XxxxService {

    @Autowired
    RestTemplate restTemplate;

    // (1)
    public static final String URL = "http://com.example.rest/book/{id}";

    public BookResponseResource getTestResponse() {
      // (2)
      Map<String, String> params = new HashMap<String, String>();
      params.put("id", "1");
      // (3)
      return restTemplate.getForObject(URL, BookResponseResource.class, params);
    }
}

(1) {id}の箇所にパラメータがバインドされる
(2) パラメータにバインドする値を設定
(2) 引数の最後にパラメータにバインドしたい値のMap<String, String>を渡す。

送信するHeader情報を変更する

送信するデータ形式をXMLなどの変更した場合や、文字コードを変更した場合、特殊なHeaderを送信したい場合など臨機応変に変更可能。

Content-Typeを変更

Content-Typeのみを変更する場合
public BookResponseResource getTestResponse(BookRequestResource request) {
    RequestEntity<BookRequestResource> requestEntity = 
        RequestEntity
          .post(new URI(URL))
          .contentType(MediaType.APPLICATION_XML) // (1)
          .body(request);

    return restTemplate.getForObject(requestEntity, BookResponseResource.class);
}

(1) Content-Typeを変更

charsetも変更する場合
public BookResponseResource getTestResponse(BookRequestResource request) {
    // (1)
    Map<String, String> prop = new HashMap<String, String>();
    prop.put("charset", "shift_jis");
    // (2)
    MediaType mediaType = new MediaType(MediaType.APPLICATION_XML, param);

    RequestEntity<BookRequestResource> requestEntity = 
        RequestEntity
          .post(new URI(URL))
          .contentType(mediaType)
          .body(request);

    return restTemplate.getForObject(requestEntity, BookResponseResource.class);
}

(1) MediaTypeのプロパティ(charset)を設定
(2) プロパティを元にMediaTypeを生成

「きほん」のん

通信先でのエラーをハンドリングする

public TestResponseResource getTestResponse() {
    // (1)
    try {
        return restTemplate.getForObject(URL, TestResponseResource.class);
    }
    catch (HttpClientErrorException e) { // (1)
        logger.error("400系エラー発生");
        throw e;
    }
    catch (HttpServerErrorException e) { // (2)
        logger.error("500系エラー発生");
        throw e;
    }
}

(1) レスポンスのHttpStatusコードが400系の場合に発生する。
(2) レスポンスのHttpStatusコードが500系の場合に発生する。

Discussion