JSONを使用したRestTemplateポストリクエスト

1. 前書き

このチュートリアルでは、Springのlink:/rest-template[_RestTemplate_]を使用して、JSONコンテンツを送信するPOSTリクエストを作成する方法を説明します。

参考文献:

Spring Boot TestRestTemplateの探索

Spring Bootで新しいTestRestTemplateを使用して簡単なAPIをテストする方法を学びます。
link:/spring-boot-testresttemplate [詳細]↠’

Spring RestTemplateエラー処理

SpringのRestTemplateでエラーを処理する方法を学ぶ
link:/spring-rest-template-error-handling [詳細]↠’

2. サンプルのセットアップ

投稿するデータを表す単純な_Person_モデルクラスを追加することから始めましょう。
public class Person {
    private Integer id;
    private String name;

    // standard constructor, getters, setters
}
_Person_オブジェクトを操作するには、_PersonService_インターフェイスと2つのメソッドを使用した実装を追加します。
public interface PersonService {

    public Person saveUpdatePerson(Person person);
    public Person findPersonById(Integer id);
}
これらのメソッドの実装は、単にオブジェクトを返します。 ここでは、このレイヤーのダミー実装を使用しているため、Webレイヤーに集中できます。

3. REST APIのセットアップ

_Person_クラスの簡単なREST APIを定義しましょう:
@PostMapping(value = "/createPerson", consumes = "application/json", produces = "application/json")
public Person createPerson(@RequestBody Person person) {
    return personService.saveUpdatePerson(person);
}

@PostMapping(value = "/updatePerson", consumes = "application/json", produces = "application/json")
public Person updatePerson(@RequestBody Person person, HttpServletResponse response) {
    response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentContextPath()
      .path("/findPerson/" + person.getId()).toUriString());

    return personService.saveUpdatePerson(person);
}
覚えているように、データをJSON形式で投稿したいと思います。 そのために、両方のメソッドに「application / json」*の値を持つ_ @ PostMapping_アノテーションに_consumes_属性を追加しました。
同様に、_produces_属性を「application / json」に設定して、JSON形式の応答本文が必要であることをSpringに伝えます。
両方のメソッドについて、_person_パラメーターにlink:/spring-request-response-body[[email protected]_]注釈を付けました。 これにより、_person_オブジェクトが_HTTP_リクエストの本文にバインドされることがSpringに通知されます。
最後に、両方のメソッドは、応答本文にバインドされる_Person_オブジェクトを返します。 link:/spring-controller-vs-restcontroller[[email protected]_]を使用してAPIクラスに注釈を付け、すべてのAPIメソッドにlink:を非表示にして注釈を付けます。 / spring-request-response-body [_ @ ResponseBody_]アノテーション。

4. _RestTemplate_の使用

これで、_Person_ REST APIをテストするためのいくつかのユニットテストを作成できます。 ここでは、_RestTemplate_によって提供されるPOSTメソッドを使用して、POST_Person_ APIにPOSTリクエストを送信しようとします:_postForObject _、_ postForEntity_、および_postForLocation_ *。
単体テストの実装を開始する前に、すべての単体テストメソッドで使用するオブジェクトを初期化するためのセットアップメソッドを定義しましょう。
@BeforeClass
public static void runBeforeAllTestMethods() {
    createPersonUrl = "http://localhost:8082/spring-rest/createPerson";
    updatePersonUrl = "http://localhost:8082/spring-rest/updatePerson";

    restTemplate = new RestTemplate();
    headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    personJsonObject = new JSONObject();
    personJsonObject.put("id", 1);
    personJsonObject.put("name", "John");
}
このセットアップメソッドに加えて、ユニットテストでJSON文字列を_JSONNode_オブジェクトに変換するために次のマッパーを参照することに注意してください。
private final ObjectMapper objectMapper = new ObjectMapper();
前述したように、* JSON形式でデータを投稿する必要があります。 これを実現するために、_APPLICATION_JSON_メディアタイプを使用して、リクエストに_Content-Type_ヘッダーを追加します*。
Springの_HttpHeaders_クラスは、ヘッダーにアクセスするためのさまざまなメソッドを提供します。 ここでは、_setContentType_メソッドを呼び出して、_Content-Type_ヘッダーを_application / json_に設定します。 リクエストに_headers_オブジェクトを添付します。

4.1. JSONの投稿_ postForObject _

_RestTemplate_‘s _postForObject_メソッドは、指定されたURIテンプレートにオブジェクトをポストすることにより、新しいリソースを作成します。 _responseType_パラメーターで指定されたタイプに自動的に変換された結果を返します。
新しい_Person_オブジェクトを作成し、この新しく作成されたオブジェクトを応答で返すために、_Person_ APIに対してPOSTリクエストを行いたいとしましょう。
*最初に、_personJsonObject_および* _ * Content-Type * ._を含むヘッダーに基づいて_HttpEntity_型の_request_オブジェクトを構築します。これにより、_postForObject_メソッドがJSON要求本文を送信できます。
@Test
public void givenDataIsJson_whenDataIsPostedByPostForObject_thenResponseBodyIsNotNull()
  throws IOException {
    HttpEntity<String> request = new HttpEntity<String>(personJsonObject.toString(), headers);

    String personResultAsJsonStr = restTemplate.postForObject(createPersonUrl, request, String.class);
    JsonNode root = objectMapper.readTree(personResultAsJsonStr);

    assertNotNull(personResultAsJsonStr);
    assertNotNull(root);
    assertNotNull(root.path("name").asText());
}
この例では、_postForObject()_メソッドは、応答本文を_String_型として返します。 _responseType_パラメーターを設定して、応答を_Person_オブジェクトとして返すこともできます。
Person person = restTemplate.postForObject(createPersonUrl, request, Person.class);

assertNotNull(person);
assertNotNull(person.getName());
実際、_createPersonUrl_ URIと一致するリクエストハンドラメソッドは、JSON形式で応答本文を生成します。 ただし、これは私たちにとっての制限ではありません。_postForObject_は、応答本文を要求されたJavaタイプに自動的に変換できます(例: _String _、_ Person_)は、_responseType_パラメーターで指定されます。

4.2. _ postForEntity _を使用したJSONの投稿

_postForObject()_と比較して、* _ postForEntity()_は応答をlink:/spring-response-entity[_ResponseEntity_]オブジェクトとして返します*。 それ以外は、両方の方法が同じ仕事をします。
_Person_ APIにPOSTリクエストを作成して、新しい_Person_オブジェクトを作成し、応答を_ResponseEntity_として返したいとします。 _postForEntity_メソッドを使用してこれを実装できます。
@Test
public void givenDataIsJson_whenDataIsPostedByPostForEntity_thenResponseBodyIsNotNull()
  throws IOException {
    HttpEntity<String> request = new HttpEntity<String>(personJsonObject.toString(), headers);

    ResponseEntity<String> responseEntityStr = restTemplate.
      postForEntity(createPersonUrl, request, String.class);
    JsonNode root = objectMapper.readTree(responseEntityStr.getBody());

    assertNotNull(responseEntityStr.getBody());
    assertNotNull(root.path("name").asText());
}
_postForObject_と同様に、_postForEntity_には、応答本文を要求されたJavaタイプに変換する_responseType_パラメーターがあります。
ここで、応答本文を_ResponseEntity <String> ._として返すことができました
_responseType_パラメーターを_Person.class_に設定することで、応答を_ResponseEntity <Person> _オブジェクトとして返すこともできます。
ResponseEntity<Person> responseEntityPerson = restTemplate.
  postForEntity(createPersonUrl, request, Person.class);

assertNotNull(responseEntityPerson.getBody());
assertNotNull(responseEntityPerson.getBody().getName());

4.3. _postForLocation_を使用したJSONの投稿

_postForObject_および_postForEntity_メソッドと同様に、_postForLocation_も、指定されたオブジェクトを指定されたURIにポストすることにより、新しいリソースを作成します。 唯一の違いは、_Location_ヘッダーの値を返すことです。
上記の_updatePerson_ REST APIメソッドで応答の_Location_ヘッダーを設定する方法を既に見たことを思い出してください。
response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentContextPath()
  .path("/findPerson/" + person.getId()).toUriString());
ここで、投稿した_person_オブジェクトを更新した後、応答の__Location __headerを返したいと考えてみましょう*。 _postForLocation_メソッドを使用してこれを実装できます。
@Test
public void givenDataIsJson_whenDataIsPostedByPostForLocation_thenResponseBodyIsTheLocationHeader()
  throws JsonProcessingException {
    HttpEntity<String> request = new HttpEntity<String>(personJsonObject.toString(), headers);
    URI locationHeader = restTemplate.postForLocation(updatePersonUrl, request);

    assertNotNull(locationHeader);
}

5. 結論

このクイックチュートリアルでは、_RestTemplate_を使用してJSONでPOSTリクエストを行う方法を検討しました。
いつものように、すべての例とコードスニペットはhttps://github.com/eugenp/tutorials/tree/master/spring-resttemplate[over on GitHub]にあります。