You are viewing documentation for a previous version of this software.

Switch to the latest stable version.

Multi Modules codegen


For multi-modules projects, Apollo Kotlin enables you to define queries in a feature module and reuse fragments and types from another module dependency. This helps with better separation of concerns and build times.

Note: this page is for sharing a schema between different modules and defining your .graphql operations in different modules. If all your .graphql files are in a single module, you can use ApolloClient like any other Kotlin dependency without any of this.

Setup

Multi-modules requires that one and only one module contains a schema. This is the schema that all other modules can reuse. In this document, we'll refer to this module as the "schema module".

Configure your schema module to generate Apollo metadata:

Kotlin
1// schema/build.gradle.kts
2apollo {
3  service("service") {
4    generateApolloMetadata.set(true)
5  }
6}

And declare your schema module as a dependency of your feature module:

Kotlin
1// feature/build.gradle.kts
2dependencies {
3    implementation("com.apollographql.apollo3:apollo-runtime:3.8.5")
4    // more regular dependencies
5
6    // Apollo dependencies
7    apolloMetadata(project(":schema"))
8    // You also need to declare the schema module as a regular dependency
9    implementation(project(":schema"))
10}

Resolving Apollo dependencies

A feature module can have any number of apollo module dependencies, each one contributing their types and fragments.

Transitive Apollo dependencies will always expose their fragments and types to the modules downstream. In other words, there is no implementation vs api concept like there is for regular dependencies. Apollo dependencies will always expose everything downstream (i.e are treated as api).

Another important thing to note is that all modules must share the same schema. Place schema.[graphqls | json] in the schema module, the module that is the higher up in the dependencies graph:

Kotlin
1// feature/build.gradle.kts
2// This module must not have a schema
3// This module can use fragments and types from 'shared' and 'schema'
4dependencies {
5    apolloMetadata(project(":shared"))
6}
7
8// shared/build.gradle.kts
9// This module must not have a schema
10// This module can use fragments and types from 'schema'
11dependencies {
12    apolloMetadata(project(":schema"))
13}
14apollo {
15  service("service") {
16    generateApolloMetadata.set(true)
17  }
18}
19
20// schema/build.gradle.kts
21// This module is the schema module
22// Place the schema in this module
23apollo {
24  service("service") {
25    generateApolloMetadata.set(true)
26  }
27}

Multiplatform

For multiplatform projects, put apolloMetadata in the top level dependencies {} block:

Kotlin
1// feature/build.gradle.kts
2// This module must not have a schema
3// This module can use fragments and types from 'shared' and 'schema'
4dependencies {
5    apolloMetadata(project(":shared"))
6}
7
8kotlin {
9    jvm()
10
11    sourceSets {
12        val commonMain by getting {
13            dependencies {
14                implementation(project(":shared")
15
16                implementation("com.apollographql.apollo:apollo-api:3.1.0")
17                api("com.apollographql.apollo:apollo-runtime-kotlin:3.1.0")
18            }
19        }
20    }
21}

Summary of different constraints:

  • All modules must apply the same version of the Apollo Gradle Plugin

  • All modules using the same schema must use the same service name

  • The schema module and only the schema module must define schema.[json | graphqls]

  • The schema module and only the schema module can call mapScalar

  • The schema module and only the schema module can define generateKotlinModels

Type clashes

When using multiple modules, Apollo Kotlin will generate models for every operation and fragment defined in this module. In addition, it's going to generate classes for schema types used by these operation. For an example, for Input Objects, Enums, Custom Scalars, etc...

If two sibling modules use the same schema type and this schema type wasn't generated upstream, each module will generate its own version of the schema type, which could clash. To prevent this, Apollo Kotlin registers a global check${service}ApolloDuplicates task that will fail if there are duplicates.

If that happens, you will need to resolve the type clash manually by forcing generation of the conflicting type in an upstream module. This is done using the alwaysGenerateTypesMatching Gradle option:

Kotlin
Groovy
1// shared/build.gradle.kts
2apollo {
3  service("service") {
4    // For an example if ReviewInput clashes
5    alwaysGenerateTypesMatching.set(listOf("ReviewInput"))
6    // You can also pass Regex patterns
7    alwaysGenerateTypesMatching.set(listOf(".*Input"))
8  }
9}
Feedback

Edit on GitHub

Forums