LoginSignup
2
3

More than 5 years have passed since last update.

HTTPクライアントライブラリFuelを初めて使ってみた2 RXJava編

Last updated at Posted at 2017-10-14

はじめに

HTTPクライアントライブラリFuelを初めて使ってみたの続編です。

Kotlin/Andorid用のHTTPクライアントライブラリであるFuelのRXJavaメソッドを試してみました。
https://github.com/kittinunf/Fuel
以降のコード例はKotlinです。

導入

Fuelの他にRX Java, GSONへをapp/build.gradleに追加します。

app/build.gradle
dependencies {
    ・・・
    // Fuel
    compile 'com.github.kittinunf.fuel:fuel:1.9.0'
    compile 'com.github.kittinunf.fuel:fuel-android:1.9.0'
    compile 'com.github.kittinunf.fuel:fuel-rxjava:1.9.0'
    // RX Java
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    // GSON 
    compile 'com.google.code.gson:gson:2.6.2'
    ・・・
}

実装

例として、Qiitaのタグ取得APIへGetリクエストを送ってみます。
https://qiita.com/api/v2/docs#タグ
例ではリクエストパラメータはページのみ指定します。
https://qiita.com/api/v2/tags?page=1
このGETリクエストのレスポンスは以下のようなJSONになります。

Response
[
    {
        "followers_count": 0,
        "icon_url": null,
        "id": "Cutter",
        "items_count": 1
    },
    {
        "followers_count": 0,
        "icon_url": null,
        "id": "ポインター",
        "items_count": 1
    }
    ・・・
]

https://qiita.com/api/v2/tags?page=a
のようにパラメータが不正であったりした場合、エラーレスポンスは以下のようなJSONになります。この場合ステータスコードは400です。

Error
{
    "message": "Bad request",
    "type": "bad_request"
}

アプリでこのタグデータとエラーレスポンスのJSONを格納するクラスをそれぞれ定義します。

Tag
// タグ
data class Tag(val followers_count: String, val icon_url: String, val id: String, val items_count: Int)
QiitaError
// エラー情報を格納
data class QiitaError(val message: String, val type: String)

APIのステータスコードが200以外の場合を例外として処理するための例外クラスを作成します。この例外クラスにAPIのエラー情報を格納します。

QiitaException
class QiitaException(val qiitaError: QiitaError) : Exception()

実際にAPIに対してリクエストを行うクラスを作成します。
Fuelのメソッドrx_responseString()が返す型はSingle<Pair<Response, Result<String, FuelError>>>ですが、
clean architecutreなどデータアクセス層を分離していくことを考え、 メソッドからはSingle<List<Tag>>を返しています。
ステータスコードが200の場合はsubscribe側のonSuccessで処理し、200以外の場合、エラーオブジェクトをsubscribe側のonErrorメソッドで処理します。このためにSingle.createとSigle.errorを使って返り値を作成します。

// データアクセス層のクラス
class Network {

    fun getTags(): Single<List<Tag>> {
        // 簡略化してパラメータは固定値
        return "https://qiita.com/api/v2/tags".httpGet(listOf("page" to "1")).rx_responseString().flatMap { p ->
            when (p.first.httpStatusCode) {
                // ステータス200は成功
                200 -> {
                    val gson = Gson()
            // タグ情報のJSONをオブジェクトへ変換
                    Single.create<List<Tag>> { e ->
                        e.onSuccess(gson.fromJson(p.second.get(), object: TypeToken<List<Tag>>(){}.type))
                    }
                }
                // 200以外はエラーとする
                else -> {
                    // エラー情報のJSONをオブジェクトへ変換し例外オブジェクトへ格納
                    val input = InputStreamReader(ByteArrayInputStream(p.first.data))
                    val gson = Gson()
                    val e2 = gson.fromJson(input, QiitaError::class.java)
                    Single.error(QiitaException(e2))
                }
            }
        }
    }
}

今回はアクティビティから呼び出します。この例では簡略化してNetworkクラスのインスタンス生成していますが、実際はDaggerでDIしたほうがいいと思います。

MainActivity
・・・
val network = Network()
network.getTags()
    // APIへのリクエストは別スレッドで処理
    .subscribeOn(Schedulers.newThread())
    // APIへの通信後はメインスレッドで処理
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        { 
           // onSuccess(List<TAG> -> Unit)
          res ->
            Log.i(TAG, res.joinToString(","))
            // 画面表示など
            ・・・

        },
        { 
            // onError
            // onError(Throwable -> Unit)なのでisで型チェック
            e ->
            if (e is QiitaException) {
                Log.i(TAG, e.qiitaError.toString())
                // エラーダイアログ表示など
                ・・・
            }

        }
    )
・・・

エラー処理はもっといいやり方があるかもしれません。何かご存知の方は教えてください。

2
3
0

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
2
3