watabee's blog

プログラミング関連のブログです

Retrofit2.5.0 でサポートされた Invocation クラスが便利そう

Retrofit2.5.0 で Invocation クラスというものが追加されたようです。

https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-250-2018-11-18

New: Invocation class provides a reference to the invoked method and argument list as a tag on the underlying OkHttp Call.
This can be accessed from an OkHttp interceptor for things like logging, analytics, or metrics aggregation.

業務の Android アプリの開発では OkHttp + Retrofit を使用しており、以前特定の API のみにヘッダを設定したいなぁ、と思ったことがありました。

今回追加された機能で簡単に実現できそうな予感がしたので試してみました。
サンプルプロジェクトはこちらです。

実装内容

GithubAPI ではアクセストークンを必要とするものがあるので、必要とする API だけヘッダにアクセストークンを設定します。

具体的に以下のように @AccessToken アノテーションを定義し、 アクセストークンが必要となる API のメソッドに付与します。

interface GithubService {

    @GET("/users/{username}/repos")
    fun getRepositories(@Path("username") username: String): Single<List<Repository>>

    @AccessToken(githubAccessToken)
    @GET("/user/repos")
    fun getAuthenticatedRepositories(): Single<List<Repository>>
}

@MustBeDocumented
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class AccessToken(val token: String)

OkHttp の Interceptor を使用して、Invocation クラスのインスタンスを取得します。
この Invocation インスタンスを使用することによりメソッドの情報が取得できるので、上記で定義した AccessToken アノテーションを参照することができます。

object AuthInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val invocation = request.tag(Invocation::class.java)
        val accessToken = invocation?.method()?.getAnnotation(AccessToken::class.java) ?: return chain.proceed(request)

        return chain.proceed(
            request.newBuilder()
                .addHeader("Authorization", "Bearer ${accessToken.token}")
                .build()
        )
    }
}

使い方によっては、今まで実装が難しかったことも簡単にできる気がします。

参考

https://gist.github.com/swankjesse/16389e5b57b04fd3ca28a798c1e90910