apollo-kotlin icon indicating copy to clipboard operation
apollo-kotlin copied to clipboard

`generateApolloMetadata` doesn't work inside a custom `service` declaration

Open benoitletondor opened this issue 2 years ago • 7 comments

Summary

For our core module, containing the schema.graphqls file I wanted to have the following setup:

apollo {
    service("public") {
        packageName.set("com.my.public.package")
        generateApolloMetadata.set(true)
    }

    service("internal") {
        srcDir("src/main/graphqlinternal")
        schemaFile.set(file("path/to/schema.graphqls"))
        packageName.set("com.my.internal.package")
        generateAsInternal.set(true)
    }
}

The goal is to expose the scalars and metadata as public, but still having some internal queries & mutation in that module that wouldn't be exposed publicly.

And this would fail as metadata would not be generated so other modules depending on those metadata using apolloMetadata(project(":core")) would fail to compile.

The workaround I found is that if I rename the public service to service (which is the default name) it works.

Version

3.5.0

Steps to reproduce the behavior

  • If your project is open source, a link to the project is greatly appreciated: https://github.com/nabla/nabla-android/blob/main/core/build.gradle

benoitletondor avatar Aug 11 '22 13:08 benoitletondor

Hi! 👋

There's a drawback to have 2 services for the same schema like this: the files are generated twice.

It would probably make more sense to have 2 modules here instead, something like:

        core-schema
         /       \
core-internal   core-public

I think ultimately you'd like the ability to have certain operations to be generated as internal, and others public, right? Whereas currently with generateAsInternal.set(true) it's all or nothing. We have this ticket that could be a good fit: it would give the ability to customize codegen.

BoD avatar Aug 11 '22 17:08 BoD

Hey @BoD , thanks a lot for your answer!

There's a drawback to have 2 services for the same schema like this: the files are generated twice.

Yeah I noticed that, but it's a drawback we can live with I think.

It would probably make more sense to have 2 modules here instead,

Yeah that would the perfect solution but since we're doing a library, a new module means a new artifact to publish and we want to limit those. So for us the drawback of having the files generated twice is less of a problem compared to having 2 new artifacts to publish.

I think ultimately you'd like the ability to have certain operations to be generated as internal, and others public, right?

Yes that would be the perfect solution for us!

benoitletondor avatar Aug 11 '22 17:08 benoitletondor

since we're doing a library, a new module means a new artifact to publish and we want to limit those.

Oh yes that makes perfectly sense! Especially if one of the modules is 'internal' it's probably nicer to not publish it 😅

Yes that would be the perfect solution for us!

So yeah I guess #4026 is the closest thing we have for now but it's only at the "idea" phase for now.

BoD avatar Aug 11 '22 17:08 BoD

So yeah I guess https://github.com/apollographql/apollo-kotlin/issues/4026 is the closest thing we have for now but it's only at the "idea" phase for now.

Yeah no worries it's not a blocker for us I just wanted to pass the word because maybe the limitation of generateApolloMetadata working only on the default service name could be documented but the perfect solution can wait.

Thanks again for your answers

benoitletondor avatar Aug 11 '22 17:08 benoitletondor

For the record, generateApolloMetadata works for all service names... BUT all services sharing the same schema have to use the same service name. So you could also name the services "public" in your others modules and it'd work too. This is required so that Gradle dependency resolution can "match" the metadata to the correct service in case you have several schemas in the same module.

martinbonnin avatar Aug 11 '22 19:08 martinbonnin

Oh I see, makes sense indeed! Thanks for the explanation

benoitletondor avatar Aug 11 '22 20:08 benoitletondor

Thinking out loud, as a possible mitigation solution, you could use packageNameFromFilePath() and put your "internal" queries in an internal subfolder:

src/main/graphql/com/example/PublicQuery.graphql
src/main/graphql/com/example/internal/PrivateQuery.graphql

Of course someone could still use PrivateQuery but the "internal" in the packageName should be an indication that it's not meant for public consumption.

martinbonnin avatar Aug 11 '22 20:08 martinbonnin

Closing this one as you can use 3.7.0 compiler hooks to add internal to only some classes.

martinbonnin avatar Feb 28 '23 12:02 martinbonnin

For an example of how to use compiler hooks, you can take a look at:

martinbonnin avatar Feb 28 '23 12:02 martinbonnin