hey quick question. do apolloUsedCoordinates suppo...
# apollo-kotlin
a
hey quick question. do apolloUsedCoordinates support multiple services?
Copy code
> No matching variant of project :domain was found. The consumer was configured to find a usage of 'apollo-used-coordinates' of a component, as well as attribute 'com.apollographql.service' with value 'api' but
but we only use the service from
api2
in that module.
m
That should work. Do you mind sharing more about your module layout?
a
Sure I’ll do so in the morning ! It was just a schema module with two schemas in different services. And having different modules included as used coordinates. They utilize 1 or both services
ok so our module layout is like this:
Copy code
schema
module1 -> schema
module2 -> schema
where:
Copy code
schema: service("api1", "api2")
module1: service("api1", "api2")
module2: service("api2")
module1 and module2 add
apolloSchema
+
implementation
on
schema
while
schema
declares
apolloUsedCoordinates
of each
module1
and
module2
m
Damn you are 100% right...
Same thing goes the other way too 😕 We can't have a feature module using 2 services referencing two different schema modules....
Now the good new is that there is certainly a workaround... let me try
Maybe this:
Copy code
dependencies {
    add("apolloApi1UsedCoordinatesConsumer", project(":module1"))
    add("apolloApi2UsedCoordinatesConsumer", project(":module1"))
    add("apolloApi2UsedCoordinatesConsumer", project(":module2"))
}
(trying to work on a reproducer)
The reproducer has only one service in each feature module but it's the same idea
It's using the low level configurations instead of the catch-all "apolloMetadata" and "apolloUsedCoordinates" configurations
The only important thing is to put add the dependencies * after * registering the services or else the configurations are not created yet
a
Ahh interesting. I’ll try it out. Thank you! I was out sick past couple days, so apologies for late acknowledgment
m
No worries at all, thanks for bringing that up! I hope you're feeling better!
a
this worked! i made a convenience function:
Copy code
/**
 * Declares apollo used coordinates for our schema. Rather than defining a bunch of "always generate types"
 */
fun DependencyHandler.api1(
    vararg projects: ProjectDependency,
) {
    projects.forEach { apolloUsed("api1", it) }
}

fun DependencyHandler.apolloUsed(service: String, project: ProjectDependency) {
    add("apollo${service.capitalized()}UsedCoordinatesConsumer", project)
}
then we just queue it up:
Copy code
api1(
        project(":homepage-graphql"),
        project(":homepage-**-graphql"),
        project(":**-graphql"),
    )
also from the docs on 3.7.0 it was not quite clear that we needed
implementation
on our schema alongside
apolloSchema
, and
apolloMetadata
might be fun to added a combination configuration that (or named better) is like:
Copy code
apolloSchemaConsumer(project(":schema"))
that does
implementation
,
apolloSchema
and
apolloMetadata
m
Awesome! Glad to hear it worked !
And sorry about the multiple configurations, etc... I know it's a bit messy. I'm reorganizing things for 4.x so that it's easier. See https://github.com/apollographql/apollo-kotlin/pull/4694
In the end it's going to look like this:
Copy code
# feature
apollo {
  service("service") {
    packageName.set("feature")
    dependsOn(project(":schema")
  }
}

# schema
apollo {
  service("service") {
    packageName.set("schema")
    # naming is up for grabs
    isADependencyOf(project(":feature")
  }
}
It's a bit unfortunate that we can't "doubly link" projects to make the
isADependencyOf
completely optional but I didn't find a way for this with Gradle configuration cache and proejct isolation aruond
a
ahh niceee
thats really cool
one more question: for the used coordinates. do intermediate modules (we have common -graphql modules) also need to declare
apolloSchema
? im guessing yes
say we have schema -> module a -> module b module b declares queries module a declares reusable fragments
m
Yes, the schema is required in both module a and module b
a
cool. thanks
m
Sure thing!
a
i think the above approach is solid. love the change (when it lands!) also to note, the coordinates approach drastically simplified our schema modules gradle file. thank you ♾️ !
m
Nice! TBH, this is (was?) one of the most hairy part of the codegen. Making everything work together and dealing with the multiple Gradle APIs was quite the beast.
a
one separate bug to report, if it is one. so ive linked up the used coordinates for first time in the project, using the configuration
apolloApi1UsedCoordinatesConsumer
. Hit build, and run into this error:
Copy code
> java.io.FileNotFoundException: /Users/**/project/**-graphql/build/generated/usedCoordinates/apollo/api1/usedCoordinates.json (No such file or directory)
if i run,
generateApiApolloUsedCoordinates
itll then work
m
Mmm that rings a bell
a
maybe i need to manually link up the gradle tasks to another one?
m
Mmm I was thinking this one maybe but since you're on 3.7.4 it should be fixed already 🤔
Can you share the full stacktrace when this happens?
a
oops. im on 3.7.1 in this branch. let me pull our latest dev which should have 3.7.4 now
m
Ah !
🤞
a
and yeah we use configuration cache. so its probably related
m
Looks really similar
a
🙏 again!
m
Also separate thing but if you have some insights about how modularization helps you, I'd love to hear any kind of feedback. It's typically really hard to measure this but if you had number like maybe "build time after changing a query in a feature module" vs "build time after changing the schema module"
If you're interested, we could even run a joint blog post or something. I feel like there's a lot to tell about the modularization story with GraphQL and you're way ahead of many teams
a
ah thank you! we don’t have separate metrics for before and after, because we’ve had modularization from the start 😏 some high level insights: 1. modularization has enabled us to logically separate our graphql queries out into feature related pieces 2. we can reuse our graphql fragments in feature modules very nicely. this works extremely well for a reusable component experiences framework ive developed at wayfair. We can then reuse fragments from union types in different queries with minimal effort to integrate UI with minimal effort. I wish i could share more publicly nod
Copy code
If you're interested, we could even run a joint blog post or something. I feel like there's a lot to tell about the modularization story with GraphQL and you're way ahead of many teams
would be happy to chat about it