Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom requestbuilder interceptors #3476

Closed

Conversation

HylkeB
Copy link

@HylkeB HylkeB commented Oct 7, 2020

What
Support custom RequestBuilder interceptors, along with the possibility to add custom parameter annotations (see other PR). The RequestBuilderInterceptor is called just before Retrofit creates an okhttp3.Request and the okhttp3.Request.Builder and retrofit.Invocation are provided.

Why
This RequestBuilderInterceptor allows developers full freedom to mutate and alter the okhttp request using their own custom annotations (both method and parameter annotations) via the Invocation class.

My first intuition was to add support for custom ParameterHandlers, but with that, you still can't modify the request based on method arguments. Also, to implement correct support for custom ParameterHandlers, the retrofit.RequestBuilder would need to be public and a lot of methods needed to be added for it to be usable. It would basically become a copy of the okhttp3.Request.Builder. For my personal usecase I actually need access to both the method and parameter annotations when mutating the request.

How
Retrofit keeps track of a list of RequestBuilderInterceptors.
These interceptors are provided to the RequestFactory.
When the Request is created as a last step the RequestBuilderInterceptors are called.

@swankjesse
Copy link
Collaborator

Did you consider using an OkHttp interceptor and @Tag ?

@HylkeB
Copy link
Author

HylkeB commented Oct 8, 2020

I have considered both.

Regarding OkHttp interceptor, I have stopped considering it because in the near future I will have to implement a custom Call.Factory where i wrap around OkHttp requests and responses, but dont let OkHttp handle them, but some third party SDK for corporate secure api calls, so in that case the interceptor wont be called.

Regarding the @Tag, its sort of possible what I want to achieve, but it's less descriptive than custom annotations. Also, with the @Tag you can only modify the tag. Even though that could functionally be enough for me, I can imagine other developers want to modify other parts of the request with custom annotations.

What I want looks something like this:

class CachedResponse<T>(
  val fromCache: Boolean,
  val response: T
)

interface SomeApi {
  @Cacheable(staleTime = 10, expireTime = 1000)
  @GET("/")
  fun getData(@ForceRefresh forceRefresh: Boolean): Single<CachedResponse<SomeResponseObject>>
}

SomeApi.getData(forceRefresh = true)

How it probably would look using the @Tag annotation:

class CacheMetadataHolder(
  val staleTime: Long,
  val expireTime: Long,
  val forceRefresh: Boolean
) {
  internal var fromCache: Boolean = false
}

interface SomeApi {
  @GET("/")
  fun getData(
    @Tag cacheData: CacheMetadataHolder
  ): Single<CachedResponse<SomeResponseObject>>
}

SomeApi.getData(CacheMetadataHolder(staleTime = 10, expireTime = 1000, forceRefresh = true))

@swankjesse
Copy link
Collaborator

Note that your custom Call.Factory can run your interceptors. That might be your best solution here.

I don‘t think we need yet another layer of indirection here.

@swankjesse swankjesse closed this Oct 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants