Kotlin/FuelでHTTPアクセスしました。

お疲れさまです。@naokiurです。
よろしくお願い致します。

今回は、KotlinでHTTPアクセスを実施したいと思います。

# 環境
* MacBook Pro (Retina 13-inch、Early 2015)
* macOS High Sierra 10.13.6
* Java 1.8.0_191
* IntelliJ IDEA CE 2018.3.4

# 実施したこと
* ローカルサーバーの作成
    * 確認用
    * GET
        * レスポンス: text
        * レスポンス: json
* クライアントの作成

# 結果
* クライアントからサーバーへHTTPリクエストを送ってレスポンスを取得することができた。

# ローカルサーバーの作成
せっかくなので、KtorでAPIサーバーを作成します。
クライアントからこれにアクセスし、確認するためです。

```FuelSampleApi.kt
package jp.ne.naokiur.sample.fuel

import com.google.gson.GsonBuilder
import io.ktor.application.Application
import io.ktor.application.call
import io.ktor.application.install
import io.ktor.features.CallLogging
import io.ktor.features.Compression
import io.ktor.features.ContentNegotiation
import io.ktor.features.DefaultHeaders
import io.ktor.gson.gson
import io.ktor.response.respond
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.routing
import java.text.DateFormat

fun Application.fuelSampleApi() {

    install(DefaultHeaders)
    install(Compression)
    install(CallLogging)
    install(ContentNegotiation) {
        gson {
            setDateFormat(DateFormat.LONG)
            setPrettyPrinting()
        }
    }

    routing {
        get("/") {
            call.respondText("fuel sample api!")
        }
        get("/text") {
            call.respondText("access Text!")
        }
        get("/json") {
            val gson = GsonBuilder().setPrettyPrinting().create()
            val res = mapOf("message" to "access json!", "a" to "1", "b" to "2")
            call.respond(gson.toJson(res))
        }
    }
}
```
GETリクエストを送信すると、
それぞれtextとJSONを返却するローカルサーバーを作成しました。

<img width="382" alt="スクリーンショット 2019-08-03 17.08.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129313/2638f33b-58bb-8c0b-823e-b2a15116f936.png">
<img width="353" alt="スクリーンショット 2019-08-03 17.08.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129313/705069c5-5086-70ae-9e99-1986b9d51f98.png">

これを確認用にしたいと思います。


# クライアントの作成
[Fuelの公式](https://github.com/kittinunf/fuel)を拝見しつつ、
作成していきます。

## レスポンス: text

### Fuelのインストール

build.gradleに追加します。

```build.gradle
buildscript {
    ext.fuel_version = '2.2.0'
    // 中略
}
dependencies {
    implementation "com.github.kittinunf.fuel:fuel:$fuel_version"
    // 中略
}
```

### クラス・メソッドの作成

HTTPアクセスするクラスを作成します。

```HttpAccessor.kt
package jp.ne.naokiur.sample.fuel

import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.result.Result

class HttpAccessor {
    fun getText(url: String): String {
        val (_, _, result) = url.httpGet().responseString()

        return when (result) {
            is Result.Failure -> {
                val ex = result.getException()
                ex.toString()
            }
            is Result.Success -> {
                result.get()
            }
        }
    }
}
```
`responseString()`は同期的に処理してくれるそうです。
Tripleで返却されるため、分解宣言をし、
今回必要としている、`Result`だけ、受け取ります。

これを実行するメソッドを作成します。

```FuelSampleMain.kt
package jp.ne.naokiur.sample.fuel

fun main() {
    val accessor = HttpAccessor()

    // Text
    val resultText = accessor.getText("http://localhost:8080/text")

    println(resultText)
}
```

## レスポンス: json

### Fuel-jsonのインストール
Fuelには、いくつものデシリアライザが用意されており、
その中でJSON形式もあります。
便利ですね。

build.gradleに追加します。

```build.gradle
buildscript {
    ext.fuel_version = '2.2.0'
    // 中略
}
dependencies {
    implementation "com.github.kittinunf.fuel:fuel:$fuel_version"
    implementation "com.github.kittinunf.fuel:fuel-json:$fuel_version" // 追加
    // 中略
}

```

### メソッドの作成
レスポンスのJSONを扱いやすいように変換した上で、
返却するメソッドにしたいと思います。

```HttpAccessor.kt
package jp.ne.naokiur.sample.fuel

import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.fuel.json.responseJson
import com.github.kittinunf.result.Result
import org.json.JSONObject

class HttpAccessor {
    // 中略
    fun getJson(url: String): JSONObject {
        val (_, _, result) = url.httpGet().responseJson()

        return when (result) {
            is Result.Failure -> {
                val ex = result.getException()

                JSONObject(mapOf("message" to ex.toString()))
            }
            is Result.Success -> {
                result.get().obj()
            }
        }
    }
}
```
メソッドに、これを実行する処理を追加します。

```FuelSampleMain.kt
package jp.ne.naokiur.sample.fuel

fun main() {
    val accessor = HttpAccessor()

    // Text
    val resultText = accessor.getText("http://localhost:8080/text")

    println(resultText)

    // JSON
    val resultJson = accessor.getJson("http://localhost:8080/json")

    println(resultJson.get("message"))
    println(resultJson.get("a"))
    println(resultJson.get("b"))
}
```

# 結果
Intellijのランナーで `FuelSampleMain.kt`を実行すると、
以下のように出力され、
アクセスできたことが確認できました。

<img width="328" alt="スクリーンショット 2019-08-03 17.24.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129313/862e98fe-927b-dfd2-8bc1-f8f6e0fa5add.png">



# 今後
* エラーハンドリングが雑なので、付け加えていきたいと思います。
* GETメソッドしか試していないため、他のメソッドも試したいと思います。
* 拡張性・再利用性のあるクラスにリファクタリングしていきたいと思います。

# 参考にさせて頂きました
* https://github.com/kittinunf/fuel
* https://github.com/kittinunf/fuel/tree/master/fuel-json