I want to use Apollo Android to query the GitHub GraphQL api, using Kotlin with the Gradle Kotlin DSL but not on Android.
Error message
I do run into a specific problem, but that's probably because there is something wrong in my setup elsewhere.
To summarize, I have a ViewLogin.graphql
file, from which a ViewLoginQuery
is generated, but when I try to use ViewLoginQuery.builder()
then unresolved reference: builder
is the problem.
As mentioned in https://github.com/apollographql/apollo-android/issues/1573, it should be possible to use Apollo Android without Android.
I'm using Arch Linux and IntelliJ, with the JS GraphQL IntelliJ plugin installed.
When writing the build file I already ran into a problem: I did not manage to avoid using the deprecated buildscript
block.
The plugin shown at https://plugins.gradle.org/plugin/com.apollographql.apollo is apparently the incubating plugin as mentioned at https://github.com/apollographql/apollo-android/issues/1573#issuecomment-575613238 which is not yet ready.
The following build file seems to apply the plugin correctly:
buildscript {
repositories {
maven {
url = uri("https://plugins.gradle.org/m2/")
}
jcenter()
}
dependencies {
classpath("com.apollographql.apollo:apollo-gradle-plugin:1.2.2")
}
}
apply(plugin = "com.apollographql.android")
plugins {
val kotlinVersion = "1.3.60"
application
kotlin("jvm") version kotlinVersion
java
idea
}
dependencies {
implementation(kotlin("stdlib"))
// Apollo and dependencies
implementation("com.apollographql.apollo:apollo-runtime:1.2.2")
implementation("com.squareup.okio:okio:2.4.3")
implementation("org.jetbrains:annotations:13.0")
testImplementation("org.jetbrains:annotations:13.0")
}
repositories {
mavenCentral()
mavenLocal()
jcenter()
}
tasks.withType<com.apollographql.apollo.gradle.ApolloCodegenTask> {
generateKotlinModels.set(true)
}
so after syncing, I have the apollo Gradle tasks available.
I installed the Apollo cli interface and then, following the Apollo docs, I ran
apollo schema:download --endpoint=https://api.github.com/graphql --header="Authorization: Bearer mytoken"
which gave me a schema.json
that I put in src/main/graphql/nl/mypackage/myapplication/schema.json
.
I have a file src/main/graphql/nl/mypackage/myapplication/ViewLogin.graphql
which contains query ViewLogin { viewer { login }}
.
IntelliJ shows an error on both viewer
and login
, saying Unknown field "viewer" on object type "Query". Did you mean "viewer"?
. But this may be a misconfiguration of the JS GraphQL plugin.
I tried to configure JS GraphQL by adding a file src/main/graphql/nl/mypackage/myapplication/.graphqlconfig
containing
{
"name": "GitHub GraphQL Schema",
"schemaPath": "schema.json",
"extensions": {
"endpoints": {
"Default GraphQL Endpoint": {
"url": "https://api.github.com/graphql",
"headers": {
"user-agent": "JS GraphQL"
},
"introspect": true
}
}
}
}
but the errors remain.
Then I executed the Gradle task generateApolloClasses
which generated a build/generated/source/apollo/classes/main/nl/mypackage/myapplication/ViewLoginQuery.kt
file.
When I open that file, no errors are shown and everything looks ok.
In a file src/main/kotlin/nl/mypackage/myapplication/GraphqlExample.kt
I tried to use the query, following the docs at https://www.apollographql.com/docs/android/essentials/get-started/#consuming-code
but when I try to use ViewLoginQuery.builder()
then builder
is not recognized (by IntelliJ, and also when I try to run it).
I tried searching in superclasses of ViewLoginQuery but I couldn't find anything about a builder.
I don't know where that builder
is supposed to be, but you can instantiate the query directly and use that.
This is an example of consumer code (last tested with version 2.1.0):
import com.apollographql.apollo.ApolloCall
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.api.Response
import com.apollographql.apollo.exception.ApolloException
import okhttp3.OkHttpClient
fun main(args: Array<String>) {
val serverUrl = "https://api.github.com/graphql"
val authHeader = args[0]
// Add authentication header for GitHub
val okHttpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val builder = chain.request().newBuilder()
builder.header("Authorization", "Bearer $authHeader")
chain.proceed(builder.build())
}
.build()
val apolloClient = ApolloClient.builder()
.serverUrl(serverUrl)
.okHttpClient(okHttpClient)
.build()
val query = ViewLoginQuery()
apolloClient.query(query).enqueue(object : ApolloCall.Callback<ViewLoginQuery.Data?>() {
override fun onResponse(dataResponse: Response<ViewLoginQuery.Data?>) {
val data = dataResponse.data
if (data == null) {
println("No data received")
println(dataResponse.errors)
} else {
println(dataResponse.data?.viewer?.login)
}
}
override fun onFailure(e: ApolloException) {
println(e.message)
}
})
}
To fix the 'unknown field' errors in the .graphql file, you have to download the schema as a schema.graphql
instead of schema.json
, see https://github.com/jimkyndemeyer/js-graphql-intellij-plugin/issues/305 for the issue report.
You also have to provide the github token in the header. Change your .graphqlconfig
to the following:
{
"name": "GitHub GraphQL Schema",
"schemaPath": "./schema.graphql",
"extensions": {
"endpoints": {
"Default GraphQL Endpoint": {
"url": "https://api.github.com/graphql",
"headers": {
"user-agent": "JS GraphQL",
"Authorization": "Bearer ${env:GITHUB_GRAPHQL_TOKEN}"
},
"introspect": true
}
}
}
}
You can now easily download the new schema by clicking the 'run introspection query' gutter icon next to the "url":
line.
You will get a popup asking for the token. Unfortunately the plugin does not yet support reading the environment variable from anywhere, see for example https://github.com/jimkyndemeyer/js-graphql-intellij-plugin/issues/285
However, Apollo Android requires a schema.json
, so you need to keep the one you downloaded!
Since Apollo Android will (at least for me) error on the schema.graphql
file, tell it to ignore that file by changing the Gradle task configuration to
apollo {
generateKotlinModels.set(true)
graphqlSourceDirectorySet.srcDir("src/main/graphql")
graphqlSourceDirectorySet.include("**/*.graphql")
graphqlSourceDirectorySet.exclude("**/schema.graphql")
}
For documentation on those options, see https://www.apollographql.com/docs/android/essentials/plugin-configuration/
To summarize: for the JS GraphQL plugin, which you want in order to easily work with graphql files, you need the schema.graphql
which you download from the .graphqlconfig
. For Apollo Android, you need the schema.json
, which you download using the Apollo cli interface.
[Edit June 2020] For Apollo Android 2, you can use the new Gradle plugin, so the complete build.gradle.kts becomes as follows:
Remember to always check for dependency updates before using, for example using the help/useLatestVersions Gradle task from the use-latest-versions Gradle plugin.
plugins {
val kotlinVersion = "1.3.72"
application
kotlin("jvm") version kotlinVersion
java
idea
// Plugin which checks for dependency updates with help/dependencyUpdates task.
id("com.github.ben-manes.versions") version "0.28.0"
// Plugin which can update Gradle dependencies, use help/useLatestVersions
id("se.patrikerdes.use-latest-versions") version "0.2.14"
id("com.apollographql.apollo") version "2.1.0"
}
dependencies {
implementation(kotlin("stdlib"))
// Apollo and dependencies
implementation("com.apollographql.apollo:apollo-runtime:2.1.0")
implementation("com.squareup.okio:okio:2.4.3")
implementation("org.jetbrains:annotations:19.0.0")
testImplementation("org.jetbrains:annotations:19.0.0")
}
repositories {
mavenCentral()
mavenLocal()
jcenter()
}
apollo {
generateKotlinModels.set(true)
graphqlSourceDirectorySet.srcDir("src/main/graphql")
graphqlSourceDirectorySet.include("**/*.graphql")
graphqlSourceDirectorySet.exclude("**/schema.graphql")
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}