Apollo GraphQL Client Code Generation Maven Plugin
Usage
A full usage example can be found in the test project
Getting Started
- Add the apollo runtime library to your project's dependencies:
<dependencies>
<dependency>
<groupId>com.apollographql.apollo</groupId>
<artifactId>apollo-runtime</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>2.8.0</version>
</dependency>
<!-- Optional, needed only for ANNOTATED nullable type-->
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>20.1.0</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
- Add the code generator plugin to your project's build:
<plugin>
<groupId>com.github.sparow199</groupId>
<artifactId>apollo-client-maven-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<rootPackageName>com.example.graphql.client</rootPackageName>
</configuration>
</execution>
</executions>
</plugin>
- Create a file
src/main/graphql/schema.json
with the JSON results of an introspection query OR you can automatically generate this file by settinggenerateIntrospectionFile
to true andschemaUrl
to your GraphQL endpoint. At build time, the plugin will query the server and install this file per the value ofintrospectionFile
. - Create files for each query you'd like to generate classes for under
src/main/graphql
:- Query file names must match the name of the query they contain
- Query files must end with
.graphql
- Any subdirectories under
src/main/graphql
are treated as extra package names to append torootPackageName
in the plugin config.
- Run
mvn clean generate-sources
to generate classes for your queries.
Configuration Options
All plugin options and their defaults:
<configuration>
<skip>false</skip>
<addSourceRoot>true</addSourceRoot>
<introspectionFile>${project.basedir}/src/main/graphql/schema.json</introspectionFile>
<generateIntrospectionFile>false</generateIntrospectionFile>
<sourceDirName>${project.basedir}/src/main/graphql</sourceDirName>
<schemaUrl>http://localhost/graphql</schemaUrl>
<schemaUrlHeaders></schemaUrlHeaders>
<useSelfSignedCertificat>false</useSelfSignedCertificat>
<rootPackageName>com.example.graphql.client</rootPackageName>
<outputDirectory>${project.build.directory}/generated-sources/graphql-client</outputDirectory>
<operationIdGeneratorClass>com.apollographql.apollo.compiler.OperationIdGenerator$Sha256</operationIdGeneratorClass>
<generateModelBuilder>true</generateModelBuilder>
<useJavaBeansSemanticNaming>true</useJavaBeansSemanticNaming>
<useSemanticNaming>true</useSemanticNaming>
<nullableValueType>JAVA_OPTIONAL</nullableValueType>
<suppressRawTypesWarning>false</suppressRawTypesWarning>
<generateKotlinModels>false</generateKotlinModels>
<generateAsInternal>false</generateAsInternal>
<generateVisitorForPolymorphicDatatypes>false</generateVisitorForPolymorphicDatatypes>
<kotlinMultiPlatformProject>false</kotlinMultiPlatformProject>
<customTypeMap></customTypeMap>
<enumAsSealedClassPatternFilters></enumAsSealedClassPatternFilters>
</configuration>
Nullable Types
Available nullable types:
ANNOTATED
APOLLO_OPTIONAL
GUAVA_OPTIONAL
JAVA_OPTIONAL
INPUT_TYPE
Properties specified as nullable in the schema will have a java 8 java.util.optional
type.
Custom Types
To use the Custom Scalar Types you need to define mapping configuration then register your custom adapter:
<configuration>
...
<customTypeMap>
<Long>java.lang.Long</Long>
</customTypeMap>
</configuration>
Using Apollo Client
Assuming a file named src/main/graphql/GetBooks.graphql
is defined that contains a query named GetBooks
against the given schema.json
, the following code demonstrates how that query could be executed.
ApolloClient client = ApolloClient.builder()
.serverUrl("https://example.com/graphql")
.okHttpClient(new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
@Override
okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
return chain.proceed(chain.request().newBuilder().addHeader("Authorization", "Basic cnllYnJ5ZTpidWJibGVzMTIz").build());
}
})
.build())
.build();
client.query(new GetBooksQuery())
.enqueue(new ApolloCall.Callback<GetBooksQuery.Data>() {
@Override public void onResponse(@NotNull Response<GetBooksQuery.Data> response) {
...
}
@Override public void onFailure(@NotNull ApolloException t) {
...
}
});
Wrap ApolloCall with CompletableFuture
If you miss apolloCall.execute method, which execute a query synchronously, you could wrap apolloCall.enqueue with a CompletableFuture and call join method to wait for the response
public class ApolloClientUtils {
public static <T> CompletableFuture<Response<T>> toCompletableFuture(ApolloCall<T> apolloCall) {
CompletableFuture<Response<T>> completableFuture = new CompletableFuture<>();
completableFuture.whenComplete((tResponse, throwable) -> {
if (completableFuture.isCancelled()) {
completableFuture.cancel(true);
}
});
apolloCall.enqueue(new ApolloCall.Callback<T>() {
@Override
public void onResponse(@NotNull Response<T> response) {
completableFuture.complete(response);
}
@Override
public void onFailure(@NotNull ApolloException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
}
Using Apollo without apollo-runtime
See documentation