Could any guidance be added for interceptors, but ...
# apollo-kotlin
s
Could any guidance be added for interceptors, but not for Http ones as described here, but adding a section about ApolloInterceptor too. More in Thread 🧵
For example now during migration, I’m looking into changing an interceptor I had here and it doesn’t feel like a simple 1-to-1 mapping (or I’m just lacking some knowledge on how to do it). Would the normal pattern be doing a map on the flow? Something like?
Copy code
override fun <D : Operation.Data> intercept(
  request: ApolloRequest<D>,
  chain: ApolloInterceptorChain,
): Flow<ApolloResponse<D>> {
  return chain.proceed(request).map { response ->
    if (notAplicableHere) return@map response // If nothing to intercept just return it as it was
    // do something else with the response if applicable
    response // ^map return the response as it was if we reached the end of the map
  }
}
And in my case where I just want to do something but not edit the response itself maybe doing an
onEach
is what I should look into?
Copy code
...
  return chain.proceed(request).onEach { response ->
    if (response.notApplicablehere) return@onEach
    //do something
  }
I am now thinking this may have more to do with me not fully understanding how this flow chain would work, but I am pretty sure more people will have the same doubts so some guidance would be really appreciated (unless it’s in the docs and I missed it?)
b
Hi! Yes what you said is correct. Another equivalent way to do it in the case where it’s not applicable would be to return immediately like:
Copy code
override fun <D : Operation.Data> intercept(
  request: ApolloRequest<D>,
  chain: ApolloInterceptorChain,
): Flow<ApolloResponse<D>> {
  if (notAplicableHere) return chain.proceed(request)
  return chain.proceed(request).onEach { response ->
    // your custom logic
  }
}
👌 1
there’s also an instance of an Interceptor used internally (for the Auto Persisted Query feature) that you can have a look at here for an example
but you’re right that we have a doc for Http Interceptors but not for Apollo ones - maybe we ought to add one with a small example 🙂
s
The example you linked is perfect, I just needed to see it somewhere being done correctly so I can draw some inspiration and stop making assumptions that I wouldn’t know are true. A small example just with a working snippet and a couple of words on how this should work would be perfect. As a side note, this wasn’t mentioned in the migration docs either, but there are some differences that maybe deserve a section? There is no longer a
ApolloInterceptorFactory
which was added with
addApplicationInterceptorFactory
, now we just add the interceptor itself, which makes me wonder if will this have any different behavior? This migration process has me at the moment with the entire project being red pretty much and I can’t start testing what I am migrating until I get the project to build again, so I’m having a hard time knowing if what I’m doing is correct or not yet 😅
m
I was somewhat hoping that the
Flow
introduction would simplify enough that the API would speak for itself but indeed coroutines API do change a lot of things...
Maybe we could add backward compatibility helpers for interceptors too to simplify a bit the migration?
In this specific case, I think the interceptor can be reduced to:
Copy code
class SunsettingInterceptor: ApolloInterceptor {
  override fun <D : Operation.Data> intercept(request: ApolloRequest<D>, chain: ApolloInterceptorChain): Flow<ApolloResponse<D>> {
    return chain.proceed(request).onEach {
      if (it.errors?.any { it.isSunsetError() } == true) {
        ForceUpgradeActivity.newInstance(context)
      }
    }
  }

  private fun Error.isSunsetError(): Boolean {
    return nonStandardFields?.get("errorCode") == "invalid_version"
  }
}
❤️ 1
s
It definitely makes things nicer, it’s just that not everyone (me included) is 100% confident in all things coroutines if that makes sense so I needed a hint at least. A backwards compatible interceptor to ease migration would be very nice for people who might have a ton of them, we just had one so it’s better to actually understand what has changed and do it by hand. Has anyone else asked about them before? Maybe people aren’t struggling with migrating them as much as I did. And thanks a lot for the last snippet, that’s exactly what I ended up with myself after the suggestions Benoit gave me, so I think this also speaks to the simplicity that you mentioned before.
👍 1
❤️ 1
m
I opened https://github.com/apollographql/apollo-kotlin/issues/3785 so we can keep track of the backward compat helper. The issue is that the 2.x interceptors will put the
Callback
API, maybe some other stuff so it might end up pulling a lot of code but it's worth exploring
🙏 1