Clean Architecture, Clean Life

仕事・個人での技術的なことつぶやきます

【Android】【Kotlin】retrofit2のつまずいたところ

Androidアプリ開発でretrofit使ってたんですが、そこで躓いた点を備忘録としてまとめておきます

クエリ部分に@Pathを使ってデータを渡せない

そのままですが、例えば下記のように@Queryでクエリパラメータを渡すことがあると思います

@GET("v1/get")
    fun searchBook(
        @Query("isbn") isbn: String
    ): Single<JsonArray>

この場合最終的なURLは {BASE_URL}/v1/get?isbn={isbn} となります これはなんの問題もないです

ただ以下のように書くと怒られます

@GET("v1/get?isbn={isbn}")
    fun searchBook(
        @Path("isbn") isbn: String
    ): Single<JsonArray>

何故かクエリを@Pathで渡そうとするとエラーになります できてもいい気がするんですけどね。なんでなんでしょうか?

ちなみにこんなエラーが出ます

must not have replace block. For dynamic query parameters use @Query.

@Urlオプション使うときはパラメータ設定ができない

上記のパラメータ設定を抽象クラスにして、それの具象クラスとして下記のような実装をしていました

class BookApiService @Inject constructor(){
    fun <S> create(serviceClass: Class<S>): S{
        val gson = GsonBuilder()
            .create()

        val retrofit = Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .baseUrl("https://api.openbd.jp/")
            .client(httpBuilder.build())
            .build()

        return retrofit.create(serviceClass)
    }

    private val httpBuilder: OkHttpClient.Builder
        get() = OkHttpClient.Builder()
            .readTimeout(30, TimeUnit.SECONDS)
}

この場合、baseurlだけが違う似たようなクラスを何個も作らないといけなくなり、あまりかっこよくないな~と思って調べたところ、@Urlオプションを見つけました こんな感じで使えます

@GET
    fun searchBook(
        @Url url: String
    ): Single<JsonArray>

そして呼び出し時に引数としてurlを入れておくとbaseurlを上書きしてくれるようです

これしか勝たん、と思って下記のように使ったら怒られました

@GET("v1/get")
    fun searchBook(
        @Url url: String,
        @Query("isbn") isbn: String
    ): Single<JsonArray>

GETパラメータと@Urlは併用できないというエラーが出ます ちなみにPOSTでも同じです

エラーはこんな感じ

@Url cannot be used with @GET URL (parameter #1)

baseurlは「/(スラッシュ」)」で終わらないといけない

もうオチが見えた方もいらっしゃるかと思いますが、次にこうしてみました

class BookApiService @Inject constructor(){
    fun <S> create(serviceClass: Class<S>): S{
        val gson = GsonBuilder()
            .create()

        val retrofit = Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .baseUrl("https://api.openbd.jp/v1/get")
            .client(httpBuilder.build())
            .build()

        return retrofit.create(serviceClass)
    }

    private val httpBuilder: OkHttpClient.Builder
        get() = OkHttpClient.Builder()
            .readTimeout(30, TimeUnit.SECONDS)
}
@GET
    fun searchBook(
        @Url url: String,
        @Query("isbn") isbn: String
    ): Single<JsonArray>

こうすると次は、ベースURLは/(スラッシュ)で終わらないとだめと怒られてしまいました エラーは下記の感じです

baseUrl must end in /

結局あきらめて具象クラスを複数作りましたとさ

いい解決策お持ちの方教えて下さいm( )m

まとめ

まだretorofit絶賛実装中なので随時更新していこうかなと思います

個人的にretrofitの英語はかなり易しいので好感が持てます エラーのときはイラっとするけど