Android Retrofit2とMoshi

# はじめに
Androidアプリの開発でAPI通信を行う際、Retrofitを使うことが多いと思います。
取得したjsonをパースする際にGsonを利用してもいいのですが、Kotlinと相性が悪いです。
そこで、Kotlinのclassへのサポートを提供しているSquareの[Moshi](https://github.com/square/moshi)を使ってjsonをパースしました。

- Kotlin 1.3.21
- Retrofit 2.5.0
- Moshi 1.5.0
- Okhttp 3.13.1

```gradle:app/build.gradle
// ...

dependencies {

    // ...

    // Retrofit
    def retrofit_version = '2.5.0'
    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"

    // Moshi
    def moshi_version = '1.5.0'
    implementation "com.squareup.moshi:moshi:$moshi_version"
    implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"

    // Okhttp
    def okhttp_version = '3.13.1'
    implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
    implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
}
```

# 受け取るJson
APIを叩いた時に受け取るJsonはこちらを想定しています。

```json:companies.json
{
    "companies": [
        {
            "id": "001",
            "name": "会社1",
            "img": "https://kaisya1"},
        {
            "id": "002",
            "name": "会社2",
            "img": "https://kaisya2"
        }
    ]
}
```

# data class
パースしてオブジェクト化するためのclassがこちらです。

```kotlin:Company.kt
data class Company (val id: String, val name: String, val img: String)
```

```kotlin:Companies.kt
data class Companies (val companies: List<Company>)
```

# Interface
Retrofit2のinterfaceはこちらです。

```kotlin:CompanyApiInterface.kt
interface CompanyApiInterface {
    @GET("companyList")
    fun getCompanyList(): Call<Companies>
}
```

# 実装例
API通信を行なうclassをこんな感じで実装してみました。

```kotlin:CompanyRepository.kt
class CompanyRepository(url: String) {

    private var retrofit: Retrofit

    init {
        val moshi = Moshi.Builder()
                .add(KotlinJsonAdapterFactory())
                .build()

        this.retrofit = Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(MoshiConverterFactory.create(moshi))
                .client(getClient())
                .build()
    }

    fun getCompanies(): Response<Companies> {
        val service = this.retrofit.create(ArticleApiInterface::class.java)
        return service.getCompanyList().execute()
    }

    private fun getClient(): OkHttpClient {
        return OkHttpClient
                .Builder()
                .connectTimeout(120, TimeUnit.SECONDS)
                .readTimeout(120, TimeUnit.SECONDS)
                .addInterceptor(HttpLoggingInterceptor().apply {
                    level = HttpLoggingInterceptor.Level.BODY
                })
                .build()
    }
}
```
利用する際はこの様に利用します。

```kotlin
private fun load(){
    try{
        val companyRepository = CompanyRepository("https://hoge")
        val response = companyRepository.getCompanies()
            if(response.isSuccessful){
                // 成功
            }else{
            
            }
    }catch (t: Throwable){
            
    }
}
```

# つまったとこ
Moshiと全く関係のない箇所でつまりました。
Retrofitのinterfaceをこの様に作成していました。

```kotlin
@GET("companyList")
fun getCompanyList(): Call<List<Company>>
```
こう書いてしまうとAPI通信は成功しますが、
Jsonの`companies`のキーに紐づく変数がなくパースに失敗します↓。
`retrofit expected begin_array but was begin_object at line 1 column 2 path $`
よってこのdata classを作成することで解決しました。

```kotlin
data class Companies (val companies: List<Company>)
```
よりよい解決方法をご存知の方は教えていただけると幸いです！