https://kotlinlang.org logo
#apollo-kotlin
Title
# apollo-kotlin
s

Stylianos Gakis

11/06/2023, 4:02 PM
Using
3.8.2
I got a root apollo module with
Copy code
...
packageName.set("octopus")
generateApolloMetadata.set(true)
generateDataBuilders.set(true)
Then in a feature module, I got
Copy code
apollo {
  service("octopus") {
    packageName.set("octopus") // Tried with "octopus.home" too, to have them be different
    generateDataBuilders.set(true)
  }
}
. In my feature module then in a test, I was trying to create an instance of a response, and it seems like it’s not generating the right thing which comes from my feature module. So in my root apollo module, I got a query which asks for a type, but only asks for a subset of the fields in there. The feature module asks for a unique field which wasn’t asked before, and the data builder does not generate the right builder. Basically in one place, for the
public fun BuilderScope.buildProductVariant(block: ProductVariantBuilder.() -> Unit)
function, the
ProductVariantBuilder
only contains the fields that are present in the home module queries. I have confirmed now that adding the field in the root module (despite not needing it there), generates the right data builder, and only the fields that I have there, not the ones that are in the feature module. Does this sound like something that I am doing wrong, or something that may be wrong with data builders in 3.x? I didn’t check with 4.x atm, but if you know for example that this is solved there then just let me know and I’ll work around it for now until I can go to 4.x.
m

mbonnin

11/06/2023, 4:06 PM
In both v3 and v4 you need to either: 1. generate all types in the root module (
alwaysGenerateTypesMatching.set(listOf("*"))
) 2. or configure the "back links" so that the root module gets the used coordinates from the feature module
2. is significantly improved in v4 so if you're already doing this, it's worth trying with v4
s

Stylianos Gakis

11/06/2023, 4:08 PM
Hmm, how does
configuring back links
look like? I don’t think I’ve read the docs around that yet 👀
m

mbonnin

11/06/2023, 4:08 PM
Or if you can't just yet, add your field manually with
alwaysGenerateTypesMatching.set(listOf("Type.yourField"))
(I think this works in V3 but wouldn't put my hand on it)
Oh yea, so that's where multimodule gets really hairy
s

Stylianos Gakis

11/06/2023, 4:09 PM
I haven’t been doing any of the above so far because for the time being we always have had the gql files all in the one big module, haven’t split them at all. I am now doing this for the first time basically, hence it’s the first time I meet this issue 😄
m

mbonnin

11/06/2023, 4:09 PM
I would workaround in V3 and only set this up once you're in v4. The configuration is substantially different
s

Stylianos Gakis

11/06/2023, 4:10 PM
Okay that’s good to know. Which part of the docs should I be looking at for this for v4? I can read up so I am ready for when we do the migration 😊
m

mbonnin

11/06/2023, 4:10 PM
That's the v4 docs
thank you color 1
Data builders are quite complex because multiple modules might contribute fields to the same type so the only solution is to generate it in the root module.
There is some stuff in v3 using Gradle
apolloUsedCoordinates
configurations or so but it's not documented and had a bunch of issues so better wait until v4
👍 1
s

Stylianos Gakis

11/06/2023, 4:13 PM
Yup, that makes sense. So in v4, you’ll do X amount of
isADependencyOf
for X feature modules you got with this configuration + 1
dependsOn
per feature module with gql files, and it should then all work well together
m

mbonnin

11/06/2023, 4:13 PM
Yes, exactly.
I'm still not completely hyped by this because it feels like there should be a way to express this bi-directional relationship in a single place but AFAIK, Gradle doesn't allow that because it breaks project isolation
s

Stylianos Gakis

11/06/2023, 4:14 PM
Sounds good, yeah. I will add a dummy query in the root module for now which queries the right things, and just not use it. And remove it on v4 then. That should work.
👍 1
Yeah, I was thinking with this if there’s a way for some in-house convention plugin to make this happen, which would maybe? work? But would probably be a per-case basis, and not really something you can provide for us I would guess.
m

mbonnin

11/06/2023, 4:16 PM
I've looked at this problem from different angles but didn't find anything. The closest is https://github.com/gradle/gradle/issues/22514 but that wouldn't help us here I think
s

Stylianos Gakis

11/06/2023, 4:16 PM
Like how some convention plugins, like the one from slack I think allows each feature module to do something like
Copy code
features {
  anvil()
  blahblah()
}
And have that maybe somehow hook everything together. But this is definitely a stretch, I am only imagining here, I do not have anything concrete on my mind. Seen something like this mentioned here https://androidstudygroup.slack.com/archives/C0SFT151T/p1674252933934949
👀 1
m

mbonnin

11/06/2023, 4:18 PM
Oh yea, that's the Groovy/Kotlin DSL interop thingie?
That's the "easy" part 😅 The "hard" part is how to do
Copy code
project(":schema").dependencies {
  add("apolloUsedCoordinates", project)
}
in a way that doesn't break all the Gradle logic
BTW, for Groovy/Kotlin DSL interop, the trick is to write all your plugin API using
block: Action<T>
parameters. Gradle will generate magic bytecode to have your function accept both a Kotlin function type (works out of the box with SAM conversion) and a Groovy closure (requires magic bytecode)
s

Stylianos Gakis

11/06/2023, 4:29 PM
I don’t know. How I understood is just project-specific DSL to setup features quickly. So I imagine perhaps for our app for example I could do
Copy code
hedvig {
  apollo()
}
Which would setup the dependencies + setup
dependsOn(project(":schema"))
Now at that point I don’t know if that convention plugin can also check all those callers who call
apollo()
and then also setup
isADependencyOf
accordingly. A question, if the root module does
isADependencyOf
for all modules? So that you can just add that and only need to care for the child modules after that? Or does that fail during compilation?
m

mbonnin

11/06/2023, 4:32 PM
I don’t know if that convention plugin can also check all those callers who call
apollo()
and then also setup
isADependencyOf
accordingly.
Yea, that's the issue sad panda . I don't think it's safe to iterate the projects from a convention plugin
root module
I try to refer it as the "schema module". It doesn't have to be your root project in the Gradle acceptation of the term
you can just add that and only need to care for the child modules after that
If you can iterate all projects, then it might work but I'm not sure how "project isolation-compatible" this is.
My hunch is that if it's allowed to iterate in the "schema module", it's probably allowed to lookup a given module from another one so might as well do everything in the convention plugin
s

Stylianos Gakis

11/06/2023, 4:33 PM
Yes sorry, when I said
root module
I did in fact mean
the root apollo module
not the actual root module. That’s what we do too.
m

mbonnin

11/06/2023, 4:33 PM
Yep, I've made the mistake multiple times 🙂 . This is why I'm forcing myself to say "schema module" now. Removes any possible confusion
Takes a while to get used to but I'll get there before I replace all the "gradle enterprises" with "develocity" 😄
😂 2
s

Stylianos Gakis

11/06/2023, 4:57 PM
“Schema module” it is, I like it more, I just couldn’t come up with it myself 😅 Oh boy, the world isn’t ready for Develocity. I certainly am not for one 😂
😄 1
y

Yang

11/06/2023, 10:41 PM
Would a settings plugin help here?
m

mbonnin

11/07/2023, 12:23 AM
Maybe? Is there anything about settings plugins that make it easier to work with project isolation?
y

Yang

11/07/2023, 1:02 AM
not sure, but IIRC you can do subproject / allprojects etc without breaking project isolation
just read https://github.com/gradle/gradle/issues/22514 again, maybe not 😅
😄 1
m

mbonnin

11/07/2023, 8:25 AM
We might as well decide to give up project isolation, I'm not sure if this will ever be a reality...
2
2 Views