Hello. This may sound like a crazy idea, but is it...
# apollo-kotlin
m
Hello. This may sound like a crazy idea, but is it possible to write an interceptor that conditionally sets a
query
Boolean!
parameter on the request? For context, I have a
fragment
that uses a conditional directive like so:
Copy code
videos @include(if: $includeListingItemsVideos) {
    id
  }
And there are numerous queries that ultimately use this
fragment
. I have updated all dependent queries to include:
Copy code
$includeListingItemsVideos: Boolean! = false
If I omit the default value, modifying all entry points to explicitly pass in this
Boolean
on the Kotlin side would require touching hundreds of files including tests.
b
It should be doable, in
ApolloInterceptor
you can craft an
ApolloRequest
with
.newBuilder()
and pass a copy of the query with the desired value for the argument. But wouldn't the default value be nicer?
m
Let's say I have the following Kotlin generated query classes:
Copy code
Query1()
Query2()
Query3()
โ€ฆ
QueryN()
I'm using the default value to avoid having to touch all
N
instantiators of these queries because there are hundreds of them including unit tests that construct these. Ultimately what I want is a centralized place where I can do:
Copy code
if feature is enabled {
  inspect if arbitrary operation has includeListingItemsVideos parameter
  if so, set it to true before making the request
} else {
  proceed as is (default value of false)
}
b
Ahh feature flags, I see ๐Ÿ‘ So yeah maybe the interceptor is the way to go.
๐Ÿ˜… 1
m
I'm trying to be mindful of writing code that is easy to delete ๐Ÿ˜‰
๐Ÿ‘ 1
The "right way" is to explicitly check the feature flag across all entry points (mind you, the feature flag check is a
suspend
call) and then explicitly pass the
Boolean
in. But as mentioned before, that would easily touch numerous files. Especially because we have a lot of unit tests that instantiate the Query models directly without using Data Builders or Test Builders.
b
yeah - compromises, as always ๐Ÿ™‚
m
With that being said, is there some further documentation on Interceptors besides https://www.apollographql.com/docs/kotlin/advanced/interceptors-http/? I'm not well-versed with the API so it is not clear at the moment, how I would achieve what I'm looking to do. ๐Ÿ™‚
b
we don't have more docs than this on interceptors. I was thinking something like this:
Copy code
class MyInterceptor : ApolloInterceptor {
    override fun <D : Operation.Data> intercept(request: ApolloRequest<D>, chain: ApolloInterceptorChain): Flow<ApolloResponse<D>> {
        val operation = when (request.operation) {
            is Query1 -> request.operation.copy(myArgument = Optional.present(true))
            is Query2 -> request.operation.copy(myArgument = Optional.present(true))
            else -> request.operation
        }
        return chain.proceed(request.newBuilder(operation).build())
    }
}
a bit tedious as you'll have to do all the cases (one per query) but not sure there's a way around it... except maybe introspection, but that's a bit "hacky"
m
Ah, so one way or another each individual query needs to be addressed.
I was hoping to be able to use
request.operation.variables(CustomScalarAdapters.Empty)
but: 1. This is just a read-only map 2. The map does not include parameters with defaults that were not explicitly set
b
yeah not sure there's a way to manipulate the variables
๐Ÿ‘ 1
m
It's looking like I may have no choice but to do things the "right way" ๐Ÿ˜… https://kotlinlang.slack.com/archives/C01A6KM1SBZ/p1715357927235299?thread_ts=1715355544.272809&amp;cid=C01A6KM1SBZ
m
AFK right now but you could manipulate variables in the HttpRequestComposer. But then it means you're potentially sending an unused variable for some queries that the server might not like
(or parse the document there to determine if sending the variable is needed)
Or you could codegen a factory function for the target queries... All of those solutions coming with some additional complexity that might or might not be worth it...