So got a question regarding having multiple servic...
# apollo-kotlin
s
So got a question regarding having multiple services. Looking at the docs, it mentions that I can put multiple ones in the gradle config, but as I understand I still then need to make a new ApolloClient for each one of them, where I pass a different
.httpServerUrl()
for each ApolloClient.Builder() right? And also make sure I use the right client for the right queries? Basically the story is that the company is starting to get into having a supergraph, but we have 1 service right now which doesn’t go through there, so we want to also depend on this supergraph now and while slowly everything is moved in there we gotta deal with both those services. Anything I am missing to make my life easier for this?
b
I still then need to make a new ApolloClient for each one of them, where I pass a different
.httpServerUrl()
for each ApolloClient.Builder() right?
Right! (technically you could have several services that point to the same server, but not sure what use-case that would be)
s
Right! So I wonder what’s the simplest way to make this happen. We will basically always be in the risk of calling the wrong query in the wrong client. Also both will be of type
ApolloClient
, so I guess gotta make our own types on top of these so that DI knows which one to provide for each case, and we need to be careful to call the right thing in the right place. I wonder if making a new module for the new service is the right approach, so that hopefully in smaller feature modules we just won’t depend on the other service which exposes the generated code which targets the “old” service.
m
Run the router in the Android app 🧌
b
our own types on top of these so that DI knows which one to provide
it's been a while since I've "_daggerred"_ but you should be able to give a name to things to distinguish between them when they have the same type
having 2 modules sound good to me too - that would avoid mistakes ... unless you have a module that depend on both 'client modules'
s
it’s been a while since I’ve “_daggerred”_
Me too, cause we are “koinering” instead 😂 But yeah we could go with a qualifier too, and not introduce a new type. Will check out what makes the most sense 😊
Oh we definitely will have a module which will depend on both, that would be our “:app” module which is the “spaghetti” module as a lot of people refer to it 😅 But for there we will just bite the bullet and be more careful
b
you could maybe make a wrapper that calls the right client depending on which operation you give it... for instance by looking at in which package the operation is (so... introspection, which is usually not advisable). To avoid introspection I think you could use compiler hooks to make your operations implement a marker interface 🤔
[with a disclaimer that the hooks are experimental 😅]
or with less magic but maybe still better than injecting 2 clients, a wrapper with 2 methods (e.g.
executeOnAbc(operation)
vs
executeOnXyz(operation)
)
a
We use dagger qualifiers for this very purpose! We made it all explicit @FederatedClient , @MonoClient apolloClient , etc
s
Oh we definitely will have a module which will depend on both, that would be our “:app” module which is the “spaghetti” module as a lot of people refer to it 😅 But for there we will just bite the bullet and be more careful
I lied. Just added a
apollo:di
module, which brings in
apollo:giraffe
and
apollo:octopus
, and only exposes a Koin module which
:app
hooks into the Koin dep graph. Now no module is depending on both :giraffe and :octopus. Therefore no way for a module to misuse this, since those modules contain the koin qualifier (It’s a normal object instead of an annotation of Dagger, but same exact story), so one can not bring in the wrong qualifier, hooray for making mistakes impossible (almost). Now if only Koin did not throw a RUNTIME 🥵 crash if someone tried to run
get<ApolloClient>()
without adding a qualifier like
get<ApolloClient>(giraffeClientQualifier)
🫣 Thanks again Andrew for giving me the confidence that this is a fine approach that someone else had tried before too. Helped me a lot to just jump straight to fixing this instead of overthinking it 🤗
a
Doesn’t koin have annotations like dagger https://insert-koin.io/docs/reference/koin-annotations/start/ That would move that (i think) to compile time
s
Yes, I remember seeing something about it, but never looked into it tbh. I haven’t seen anyone in the wild use it, and considering some past experiences with backwards incompatible koin version upgrades and so on, if anything I’m pretty scared to adopt this. Might be something to give a try at some point in the future if I find the time 👀