[Android] WebAPIでのサーバー接続

Androidアプリから、APIでWebサーバーへアクセスするライブラリ sankosc/webapi-clientの紹介となります。Kotlinです。

- Kotlin: 1.4.10
- kotlinx.serialization: 1.0.1

このライブラリの特徴は
- jsonの解析はKotlinx Jsonで自動で行う。データ構造だけ定義します。
- 通信のリトライと、AccessTokenのRefreshの処理を半自動で行います。
- バックグラウンドにて実行します。
- 通信成功、失敗の処理をイベントとして渡します。そのイベントはUIスレッドで呼び出されます。

## インストール方法
[Kotolinx Json](https://github.com/Kotlin/kotlinx.serialization)を使用しますので、そのインストールも併せて行います。

プロジェクトのbundle.gradleとアプリのbundle.gradleを編集

```gradle:bundle.gradle(app)
plugins {
    id 'org.jetbrains.kotlin.plugin.serialization' version '1.4.10'
}

dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"
    implementation 'jp.co.sankosc:webapi-client:1.1.0'
}
```

## パーミッション追加
AndroidManifest.xmlにパーミッションを追加します。

```xml:AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
```

## データ定義
データ定義は[Kotolinx Json](https://github.com/Kotlin/kotlinx.serialization)で行います。
詳しい定義方法はこちらをご参照ください：[Kotolinx Json](https://github.com/Kotlin/kotlinx.serialization)

```kotlin:sample
import kotlinx.serialization.*

@Serializable
data class Message(
	val message: String?
)

@Serializable
data class Login(
    val email: String,
    val password: String
)

@Serializable
data class Token(
    @SerialName("access_token")
    val accessToken: String
)
```

## Get
Genericでデータ構造を指定。APIのURLと成功、失敗時のイベントハンドラを引数で渡します。
成功時には、イベントハンドラに指定した構造のデータが渡されます。

```kotlin:sample
val url = "https://develop.sankosc.co.jp/apitest/api/hello"
val client = WebApiClient()
client.get<Message>(url, {
    // Success
    println(it.message)
}, {
    // Error
    it.printStackTrace()
})
```

## Post
Genericでデータ構造を指定。APIのURLと送信データ、成功、失敗時のイベントハンドラを引数で渡します。
成功時には、イベントハンドラに指定した構造のデータが渡されます。

```kotlin:sample
val url = "https://develop.sankosc.co.jp/apitest/api/echo"
val client = WebApiClient()
client.post<Message, Message>(url, Message("post data"), {
    // Success
    println(it.message)
}, {
    // Error
    it.printStackTrace()
})
```

## エラー処理
失敗時には、発生した例外がハンドラに渡されます。
サーバーエラーの場合は、WebApiClientExceptionが渡されます。
WebApiClientExceptionは、サーバーのステータスコードを含みます。
例外は、Exceptionとして渡されるので、必要であればキャストして使用します。

```kotlin:例）エラー処理
client.get<Message>(url, {
}, {
    // Error
    if (it is WebApiClientException) {
        println(it.code)
    }
})
```


## 認証APIへのアクセス
Login処理などで取得したAccessトークンをインスタンスに設定してGet, Postを使用します。
そうするとヘッダに`Authorization: Bearer [Access Token]`を付けてサーバーにアクセスするようになります。

```kotlin:例）ログイン処理
val url = "https://develop.sankosc.co.jp/apitest/api/login"
val client = WebApiClient()
val data = Login("sample@sankosc.co.jp", "sample123")
client.post<Login, Token>(url, data, {
    client.accessToken = it.accessToken
}, {
    it.printStackTrace()
})
```

AccessTokenは、アプリ起動時などに保存しておいたものをコンストラクタにて設定することもできます。

```kotlin:sample
val client = WebApiClient(accessToken = "[保存しておいたトークン]")
```

## 認証エラーの処理
認証エラーの処理は、WebApiClientインスタンス生成時にコンストラクタを通して設定します。

```kotlin:sample
val client = WebApiClient(handleAuthFail = {
    // 認証エラー処理
})
```


## AccessTokenのリフレッシュ
AccessTokenのリフレッシュの処理は、WebApiClientインスタンス生成時にコンストラクタを通して設定します。設定したハンドラは、サーバーからステータスコード401が返されたときに呼び出されます。

このハンドラ(handleTokenExpired)は、引数を２つもちます。呼び出し元のWebApiClientインスタンスとリフレッシュしたトークンを渡すonRefreshed関数です。onRefreshed関数は、呼び出されたときに、認証切れになる直前に呼ばれていたAPIを再度自動で呼び出します。


```kotlin:トークンリフレッシュの例
val client = WebApiClient(handleTokenExpired= {client, onRefreshed ->
    // トークンリフレッシュ処理
    val url = "https://develop.sankosc.co.jp/apitest/api/refresh"
    client.refresh<Token>(url, {
        onRefreshed(it.accessToken)
    }, {
        it.printStackTrace()
    })
})
```

トークンのリフレッシュには、通常のget, postメソッドではなくrefreshメソッドを使います。
get, postメソッドとrefreshメソッドは、機能はまったく一緒ですが認証エラー時の処理が違います。

## おしまい
もしご興味ある方は、こちらに他のパラメータも記載していますのでご参照ください。
GitHub: https://github.com/sankosc/webapi-client-android

また確認用のAPIサーバーを準備していますので、こちらで試して頂けたら幸いです。
APIサーバー https://develop.sankosc.co.jp/apitest/

ありがとうございました。