9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Kotlin + Rest TemplateでのHttpリクエスト(GET編)

Last updated at Posted at 2019-07-06

Rest Templateとは

Rest TemplateはREST APIを呼び出すためにSpring Frameworkが提供しているHTTPクライアントです。
Httpヘッダやボディ部を設定し、指定のURLにGETまたはPOSTで送信、返ってきた結果をjsonやobjectとして取得するなどが主な機能として挙げられます。
雑にまとめてしまえばcurlコマンドをプログラムで叩くためのものです。

目次

・環境
・Beanの設定
・getForObject
・exchange
 ・応用編
・おまけ
・参考文献

環境

Kotlin:1.3.21
Spring Boot:2.1.5

Beanの設定

(※ご指摘のコメントをいただいたので追記。dais39さん、ありがとうございます。)

デフォルトのSpring BootではRestTemplateのBeanは自動で生成されないので、そのままだとDIコンテナから使用することができません。
なのでRestTemplateBuilderを使用してBeanをDIコンテナに登録します。

RestConfig.kt
@Configuration
class RestConfig{
  @Bean
  fun restTemplate(builder: RestTemplateBuilder): RestTemplate{
    return builder.build()
  }
}

今回は@Configurationクラスを用いて定義しました。

getForObject

get送信をする方法にはgetForObjectメソッドを使う方法とexchangeメソッドを使う方法の二種類があります。
主にgetForObjectはリクエストヘッダを送る必要がない場合に使用されます。

今回はSpring Bootが提供しているhttp://gturnquist-quoters.cfapps.io/api/randomにアクセスしてjsonと自作のオブジェクトSampleObjectを取得してみます。

SampleController.kt
import ...

@RestController
// DIコンテナに登録されているRestTemplate()を注入します。
class SampleController(private val restTemplate: RestTemplate) {

    // リクエスト送信先のURLを設定します。
    private val uri: String = "http://gturnquist-quoters.cfapps.io/api/random"

    // jsonファイルでのレスポンス取得
    @GetMapping("/get/json")
    fun getJson(): String? {
        return restTemplate.getForObject(uri, String::class.java)
    }

    // objectでのレスポンス取得
    @GetMapping("/get/object")
    fun getObject(): String? {
        val sampleObject = restTemplate.getForObject(uri, SampleObject::class.java)

        return sampleObject.quote
    }
}
SmapleObject.kt
import ...

data class SampleObject (
    val type: String,

    val value: Value
)

data class Value (
    val id: Int,

    val quote: String
)

これlocalhost:8080/get/jsonにアクセスするとjsonファイルが、localhost:8080/get/objectにアクセスするとランダムで表示されるquoteの値が表示されるようになりました。

もしクエリパラメータも送信したい場合はURLに文字列を合体させるか、exchangeの項目で説明するUriComponentsBuilderを使用しましょう。

exchange

exchangeメソッドはGET、POSTどちらでも送信することができます。
主にリクエストヘッダを用いてBasic認証やOAuth認証をする必要がある際に使用されます。

SampleController.kt
import ...

@RestController
class SampleController(private val restTemplate: RestTemplate) {

    private val uri: String = "http://gturnquist-quoters.cfapps.io/api/random"

    @GetMapping("/get/exchange")
    fun exchange(): ResponseEntity<String> {
        return rt.exchange(url, HttpMethod.GET, null, String::class.java)
    }

localhost:8080/get/exchangeにアクセスするとResponseEntity型の結果が返されます。(見た目はjsonとほぼ一緒)

応用編

以下のコードでは次のようなことを行なっています。

1.UriComponentsBuilderを使って送信先URIの設定(パスやクエリーの設定)
2.リクエストヘッダの設定(Basic認証の準備)
3.exchangeメソッドでResponseEntityを取得し、それのbody部分のみ(json)を取得

認証が必要ないい感じのAPIがなかったため、今回は適当な架空のURLを設定しました。
また処理を理解しやすくするためにかなり助長に書いています。

SampleController.kt
import ...

@RestController
class SampleController(private val restTemplate: RestTemplate) {

    @GetMapping("/get/exchange/hoge")
    fun getExchange(): String? {

        // 1.リクエスト送信先のURLを設定します。
        // リクエスト送信先のベースURLを設定します。
        private val baseUri: String = "http://hogehoge.com"

        // 送信先のパスとクエリーを設定します。
        val getInstanceUrl = UriComponentsBuilder.fromHttpUrl(baseUri)
                .path("/api/fuga")
                .queryParam("comment", "test-text")
                .build()
                .toUri()
        // これで getInstanceUrl = "http://hogehoge.com/api/fuga?comment=test-text" となります。


        // 2.リクエストヘッダを設定します。
        // Basic認証の設定
        val userid: String = "1234567890"
        val password: String = "pass_word"

        // バイト列に変換してBase64でエンコード
        val plainCredentials: String = userid + ":" + password
        val base64Credentials: String = Base64.getEncoder()
                .encodeToString(plainCredentials.getBytes(StandardCharsets.UTF_8))

        // AuthorizationヘッダにBasic認証の資格情報を設定する。
        val headers = HttpHeaders()
        headers.set("Authorization", "Basic " + base64Credentials)

        // HttpEntityにセット。
        val entity: HttpEntity<String> = HttpEntity(headers)


        // 3.やっとexchangeメソッドの出番
        // 引数にURL, 送信メソッド, Entity, レスポンスデータの型をそれぞれ指定します。
        // レスポンスはResponseEntity<指定した型>になります。
        val responseEntity: ResponseEntity<String> =  restTemplate.exchange(getInstancesURL, HttpMethod.GET, entity, String::class.java)

        // bodyメソッドを使用することでbody部のjsonのみを出力します。
        return responseEntity.body
    }
}

複数のクエリパラメータを使用したい場合

複数のクエリを送信したい場合queryParamメソッドを何度も使用するのは面倒です。
なのでqueryParamsメソッドを使用します。
このメソッドは引数がMultiValueMap<String, String>なので注意しましょう。

        val queryParams: Map<String, String> = mapOf("name" to "taro", "age" to "20")

        val uriParams: MultiValueMap<String, String> = LinkedMultiValueMap()
        queryParams.forEach { key, value -> uriParams.add(key, value) }

        val getInstancesURL = UriComponentsBuilder.fromHttpUrl("http://hogehoge.com/api/fuga")
            .queryParams(uriParams)
            .build()
            .toUri()

        // getInstanceUrl = "http://hogehoge.com/api/fuga?name=taro&age=20"

OAuth認証を行いたい場合

今度はBasic認証ではなくOAuth認証に変更してみます。

        val accessToken: String = "abc1234567890"

        val headers = HttpHeaders()
        headers.set("Authorization", "Bearer $accessToken")

        // HttpEntityにセット。
        val entity: HttpEntity<String> = HttpEntity(headers)

おまけ

オブジェクトとして取得する際にdata classで設定されていない値が帰ってきた場合の処理方法。

こんな感じでdata classを作った時に

SmapleObject.kt
import ...

data class SampleObject (
    val type: String,

    val value: Value
)

data class Value (
    val id: Int,

    val quote: String
)

こんな感じのjsonを取得すると

ResponseJson
{
    "type": "success", 
    "value": { 
       "id": 1, 
       "quote": "test dummy." 
    } 
    "created_at": 1476294126
} 

こんな感じのエラーが出てきます。

Unrecognized field "created_at" (Class jp.example.SampleObject), not marked as ignorable

なのでそんな時は以下のようにして、未定義の値をスルーするようにしましょう。

SampleObject.kt
@JsonIgnoreProperties(ignoreUnknown=true)
data class SampleObject (
...
)

参考文献

5.17. RESTクライアント(HTTPクライアント)
8.Springが用意するWEBクライアント(RestTemplate)の使い方
Spring BootでRestTemplateを使ってREST APIを呼び出す方法
SpringBoot:外部のサービスに接続
Get and Post Lists of Objects with RestTemplate
Spring MVC+RestTemplateで配列JSONをJavaBeanの配列又はListに変換する
かんたん!KotlinでJSONパース【Jackson】
Spring解体新書
Jackson の痒いところ Tips
Jackson使い方メモ
jacksonでデシリアライズする際に未知のプロパティを無視する
35. Calling REST Services with RestTemplate : Part IV. Spring Boot features

9
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?