Retrofit2のIntercepterを使ってヘッダーをつける(Kotlin)

##やりたいこと

Retrofit2を使って通信をする時に、 「アクセストークンがあるかどうか」など状況に応じてヘッダーを付与する。

ただし、 ` @Headers `アノテーションは使わずに ` Interceptor ` を使う。

##失敗したこと

` OkHttop.builder ` と ` Retrofit.Builder ` は共通インスタンスで持っておいて、 後からOkHttop.builderにInterceptorを追加しようとしたらダメでした。 

```kotlin

    /**
     * 認証ヘッダーなしのサービスクラス
     */
    val mDataSource: HogeServiceClass by lazy {
        val authClient = mClientBuilder.build()
        val mRetrofit = mRetrofitBuilder.client(authClient).build()
        mRetrofit.create(HogeServiceClass::class.java)
    }

    /**
     * 認証ヘッダーありのサービスクラス
     * 後からインターセプターを追加しても反映されず、失敗
     */
    val mAuthDataSource : HogeServiceClass by lazy{
        // Interseptorを追加
        val authClient = mClientBuilder.addInterceptor(mInterceptor).build()
        val mRetrofit = mRetrofitBuilder.client(authClient).build()
        mRetrofit.create(HogeServiceClass::class.java)
    }


```

> OkHttpClient maintains a list of the interceptors which you can access, however it is an unmodifiable collection.
https://stackoverflow.com/a/47394293/8800049

とのことで、どうやら**OkHttpClientは一度インスタンス化してしまうと後からInterceptor自体を追加することは出来ない**ようです。

ダメだったコード全体は最下部に書いてます。


OkHttpClientのインスタンスをもう一個別に作ればうまく行きますが、なんかスマートじゃない。
そもそもサービスクラスのインスタンスを二つ作って使い分けるのもスマートじゃない。


## 解決策

**Interceptorの定義内で条件分岐する**ことで簡単に解決しました。

```kotlin

    private val mInterceptor by lazy {
        Interceptor { chain ->
            val original = chain.request()

            if(this.accessToken.isNotEmpty()){
                chain.proceed(
                        original.newBuilder()
                                .header("Authorization", this.accessToken)
                                .method(original.method(), original.body())
                                .build()
                )
            }else{
                chain.proceed(
                        original.newBuilder()
                                .method(original.method(), original.body())
                                .build()
                )
            }
        }
    }

```

こうすることで、サービスクラスは一つで良いし、スッキリしました。

以下のようにアクセストークンを一度セットすれば、以降の通信は自動で全部認証のヘッダーが付与されます。

```kotlin
ServiceGenerator.accessToken = "hogehoge"
```


## 成功したコード全体

```kotlin

import com.facebook.stetho.okhttp3.StethoInterceptor
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import jp.co.jp.co.hoge.foo.HogeServiceClass
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory


object ServiceGenerator
{
    val moshi by lazy {
        Moshi.Builder()
                .add(KotlinJsonAdapterFactory())
                .build()
    }

    var accessToken: String = ""

    private val mInterceptor by lazy {
        Interceptor { chain ->
            val original = chain.request()

            //アクセストークンがあればヘッダーに付与
            if(this.accessToken.isNotEmpty()){
                chain.proceed(
                        original.newBuilder()
                                .header("Authorization", this.accessToken)
                                .method(original.method(), original.body())
                                .build()
                )
            }
            //それ以外はヘッダーを付与しない
            else{
                chain.proceed(
                        original.newBuilder()
                                .method(original.method(), original.body())
                                .build()
                )
            }
        }
    }

    private val mClient by lazy {
        val logging = HttpLoggingInterceptor()
        logging.level = HttpLoggingInterceptor.Level.BODY

        OkHttpClient.Builder()
                .addInterceptor(mInterceptor)
                .addInterceptor(logging)
                .addNetworkInterceptor(StethoInterceptor())
                .build()
    }

    private val mRetrofit by lazy {
        Retrofit.Builder()
                .baseUrl(BuildConfig.API_BASE_URL)
                .addConverterFactory(MoshiConverterFactory.create(moshi))
                .client(mClient)
                .build()
    }

    val mDataSource by lazy {
        mRetrofit.create(HogeServiceClass::class.java)
    }
}

```



##ダメだったコード全体
```kotlin
import com.facebook.stetho.okhttp3.StethoInterceptor
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import jp.co.jp.co.hoge.foo.HogeServiceClass
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory


object ServiceGenerator
{
    val moshi by lazy {
        Moshi.Builder()
                .add(KotlinJsonAdapterFactory())
                .build()
    }

    var accessToken: String = ""


    private val mInterceptor: Interceptor by lazy {
        Interceptor { chain ->
            val original = chain.request()
            chain.proceed(
                    original.newBuilder()
                            .header("Authorization", this.accessToken)
                            .method(original.method(), original.body())
                            .build()
            )
        }
    }

    private val mClientBuilder: OkHttpClient.Builder by lazy {
        val logging = HttpLoggingInterceptor()
        logging.level = HttpLoggingInterceptor.Level.BODY

        OkHttpClient.Builder()
                .addInterceptor(logging)
                .addNetworkInterceptor(StethoInterceptor())
    }

    private val mRetrofitBuilder: Retrofit.Builder by lazy{
        Retrofit.Builder()
                .baseUrl(BuildConfig.API_BASE_URL)
                .addConverterFactory(MoshiConverterFactory.create(moshi))
    }

    /**
     * 認証ヘッダーなしのサービスクラス
     */
    val mDataSource: HogeServiceClass by lazy {
        val authClient = mClientBuilder.build()
        val mRetrofit = mRetrofitBuilder.client(authClient).build()
        mRetrofit.create(HogeServiceClass::class.java)
    }

    /**
     * 認証ヘッダーありのサービスクラス
     * 後からインターセプターを追加しても反映されず、失敗
     */
    val mAuthDataSource : HogeServiceClass by lazy{
        val authClient = mClientBuilder.addInterceptor(mInterceptor).build()
        val mRetrofit = mRetrofitBuilder.client(authClient).build()
        mRetrofit.create(HogeServiceClass::class.java)
    }
}

```