Description
What kind of issue is this?
-
Question. This issue tracker is not the place for questions. If you want to ask how to do
something, or to understand why something isn't working the way you expect it to, use Stack
Overflow. https://stackoverflow.com/questions/tagged/retrofit -
Bug report. If you’ve found a bug, spend the time to write a failing test. Bugs with tests
get fixed. Here’s an example: https://gist.github.com/swankjesse/6608b4713ad80988cdc9 -
Feature Request. Start by telling us what problem you’re trying to solve. Often a solution
already exists! Don’t send pull requests to implement new features without first getting our
support. Sometimes we leave features out on purpose to keep the project small.
there are cases when @Query
is not enough and you would like to perform more sophisticated computations of query based on the method parameter. I have a use case in a feed reader implementing the defunct Google reader API. If you want to mark an article as read, you must hit the endpoint reader/api/0/edit-tag
with query parameter a
set to user/-/state/com.google/read
. If you want to mark it as undread, though, you must use query parameter r
.
Here is a rough implementation I made to solve that case using an interceptor:
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class QueryTransformer(val value: KClass<out QTransformer<out Any>>)
interface QTransformer<T> {
fun transform(param: T): List<Pair<String, String>>
}
class APIInterceptor(): Interceptor {
lateinit var service: API
override fun intercept(chain: Interceptor.Chain): OkHttp3Response {
val request = chain.request()
val invocation = request.tag(Invocation::class.java)!!
val method = invocation.method()
val builder = request.newBuilder()
var reqUrl = request.url()
method.parameterAnnotations.forEachIndexed {index, annotations ->
val annotation = annotations.find {it is QueryTransformer}
if(annotation != null && annotation is QueryTransformer) {
val parameter = invocation.arguments()[index]!!
val parameterType = method.parameterTypes[index]!!
val transformer = annotation.value.primaryConstructor!!.call()
@Suppress("UNCHECKED_CAST")
val queryParams = transformer.javaClass.getMethod("transform", parameterType)
.invoke(transformer, parameter) as List<Pair<String, String>>
queryParams.forEach {
reqUrl = reqUrl.newBuilder().setQueryParameter(it.first, it.second).build()
}
}
}
return builder.url(reqUrl).build().let {chain.proceed(it)}
}
}
It would be nice to have it natively in Retrofit because currenlty, this implementation forces me to use it in combination with @Query
.