1

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.

Setup

As mentioned in https://github.com/apollographql/apollo-android/issues/1573, it should be possible to use Apollo Android without Android.

Environment

I'm using Arch Linux and IntelliJ, with the JS GraphQL IntelliJ plugin installed.

Gradle Kotlin DSL build file

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.

Downloading the schema

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.

Example query

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.

Execute the query

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.

PHPirate
  • 7,023
  • 7
  • 48
  • 84

1 Answers1

5

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"
}
PHPirate
  • 7,023
  • 7
  • 48
  • 84