Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to define introspection endPoint for each build variant separately? #4490

Closed
amansaryal opened this issue Nov 3, 2022 · 9 comments
Closed

Comments

@amansaryal
Copy link

amansaryal commented Nov 3, 2022

I use introspection to download schema. The endpoint for which changes for every build variant.
I want to know how can I set the schema endpoint dynamically in my gradle script for each build variant in my app?

@BoD
Copy link
Contributor

BoD commented Nov 4, 2022

Hi! 👋

When configuring your services you can add an introspection block specific to each service.

If you're already using createAllAndroidVariantServices this could be done like this:

apollo {
    createAllAndroidVariantServices(".", "") {
        packageName.set("com.example.apollokotlin.graphql")
        if (name.startsWith("debug")) {
            srcDir(file("src/debug/graphql/"))
            introspection {
                endpointUrl.set("https://example.com/debug")
                schemaFile.set(file("src/debug/graphql/schema.graphqls"))
            }
        } else if (name.startsWith("prod")) {
            srcDir(file("src/prod/graphql/"))
            introspection {
                endpointUrl.set("https://example.com/prod")
                schemaFile.set(file("src/prod/graphql/schema.graphqls"))
            }
        } else if (name.startsWith("release")) {
            srcDir(file("src/release/graphql/"))
            introspection {
                endpointUrl.set("https://example.com/release")
                schemaFile.set(file("src/release/graphql/schema.graphqls"))
            }
        }
    }
}

Note that this creates a service for each variants, including the test ones. If you don't need this granularity you could declare the services manually, like so:

    apollo {
        service("debug") {
            srcDir(file("src/debug/graphql/"))
            packageName.set("com.example")
            outputDirConnection {
                connectToAndroidSourceSet("debug")
            }
            introspection {
                endpointUrl.set("https://example.com/debug")
                schemaFile.set(file("src/debug/graphql/schema.graphqls"))
            }
        }
        service("release") {
            srcDir(file("src/release/graphql/"))
            packageName.set("com.example")
            outputDirConnection {
                connectToAndroidSourceSet("release")
            }
            introspection {
                endpointUrl.set("https://example.com/release")
                schemaFile.set(file("src/release/graphql/schema.graphqls"))
            }
        }
    }

This will add gradle tasks named downloadDebugApolloSchemaFromIntrospection, downloadReleaseApolloSchemaFromIntrospection, etc.

@amansaryal
Copy link
Author

Thanks! that works.
However, this relies on an implementation detail which I think is bad. Could we not have the variant name passed to the action block?

@BoD
Copy link
Contributor

BoD commented Nov 4, 2022

If "" is passed as the suffix, then the service name will be the variant name.

It's true that using this relies on knowing the implementation though. Passing the variant name to the lambda is a good idea, but it may be difficult to make this change in a compatible way. It may be something we can add to the next major version though!

@amansaryal
Copy link
Author

Sounds good.
Closing this issue now. Thanks!

@martinbonnin
Copy link
Contributor

martinbonnin commented Nov 4, 2022

@amansaryal Out of curiosity, how different are your different schemas? Do you also need different queries per variant?

If your use case is debug using the pre-prod schema and release using the production one, then I'd recommend using the 2nd approach from @BoD above, specifying explicit "debug" and "release" services.
We found out that using createAllAndroidVariantServices is a waste in most cases because it will create too many codegen tasks most of the times (debug, release, debugUnitTest, debugAndroidTest in a minimal setup) when all you need is 2 codegen tasks.

@BoD BoD mentioned this issue Nov 4, 2022
33 tasks
@amansaryal
Copy link
Author

@martinbonnin correct. The second approach is what I'm going with as well. createAllAndroidVariantServices not only creates too many tasks, it also prevents me from keeping a common srcDir for my schema (because of the code below)

variant.sourceSets.forEach { sourceProvider ->
          service.srcDir("src/${sourceProvider.name}/graphql/$sourceFolder")
        }

I'm assuming that with schemas in different srcDir for each variant, I'll also have to copy my query and mutation files to all of those directories, which is unnecessary since those queries/mutations are not going to change.

Here's the use case in a nutshell:

I want a common srcDir for each build variant.
Ex: src/main/graphql

I should be able to configure introspection endpoint for each build variant.
Introspection should overwrite the schema.[ext] in my srcDir whenever I switch variants.

@martinbonnin
Copy link
Contributor

Gotcha. Many thanks for the additional context 🙏 .

Introspection should overwrite the schema.[ext] in my srcDir whenever I switch variants.

I think that's the key point. If you have shared queries with different schemas, ideally you should put the schemas outside your queries dir:

src/main/graphql/query1.graphql
src/main/graphql/query2.graphql
...

src/debug/graphql/schema.graphqls
src/release/graphql/schema.graphqls

In that case, I'd recommend doing something like this (factoring code using a nice Kotlin function):

fun ApolloExtension.createService(sourceSet: String) {
  service(sourceSet) {
    srcDir(file("src/main/graphql/")) // You can actually omit this since it's the default
    schemaFile.set(file("src/$sourceSet/graphql/schema.graphqls")) // This is required
    packageName.set("com.example")
    outputDirConnection {
      connectToAndroidSourceSet(sourceSet)
    }
    introspection {
      if (sourceSet == "debug") {
        endpointUrl.set("https://example.com/debug")
      } else {
        endpointUrl.set("https://example.com/release")
      }
      schemaFile.set(file("src/$sourceSet/graphql/schema.graphqls"))
    }
  }
}
apollo {
  createService("debug")
  createService("release")
}

All in all, I think we could certainly deprecate createAllVariantServices. This was added in an effort to stay backward compatible with v2 but I think this is misleading in most cases.

@amansaryal
Copy link
Author

So my assumption was wrong, we can indeed keep the queries and the schema in different places. Gotcha!
Thanks for this @martinbonnin!

@martinbonnin
Copy link
Contributor

Yes indeed! The plugin tries to find a schema in srcDir by default but you can override this with schemaFile

@bignimbus bignimbus mentioned this issue Jul 25, 2024
19 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants