You're viewing documentation for a version of this software that is in development. Switch to the latest stable version
/
Launch Apollo Studio

Queries


Fetching data in a predictable, type safe way is one of the core features of Apollo Android. In this guide, you'll learn how to Query GraphQL data and use the result in your application.

This page assumes some familiarity with building GraphQL queries. If you'd like a refresher, we recommend reading this guide and practicing running queries in GraphiQL. Since Apollo queries are just standard GraphQL, anything you can type into the GraphiQL query explorer can also be put into .graphql files in your project.

The following examples assume that you've already set up Apollo Android for your Android/Kotlin application. Read our getting started guide if you need help with either of those steps.

Apollo-android takes a schema and a set of .graphql files and uses these to generate code you can use to execute queries and access typed results.

All .graphql files in your project (or the subset you specify as input to apollo-codegen if you customize the script you define as the code generation build phase) will be combined and treated as one big GraphQL document. That means fragments defined in one .graphql file are available to all other .graphql files for example, but it also means operation names and fragment names have to be unique and you will receive validation errors if they are not.

Creating queries

Queries are represented as instances of generated classes conforming to the Query protocol. Constructor arguments can be used to define query variables if needed. You pass a query object to ApolloClient#query(query) to send the query to the server, execute it, and receive results.

For example, if you define a query called GetHero:

query HeroQuery($id: String!) {
  hero(id: $id) {
    id
    name
    appearsIn
  }
}

Here, query is the operation type and HeroQuery is the operation name. Apollo-android will generate a HeroQuery class that you can construct (with variables) and pass to ApolloClient#query(query):

val response = apolloClient.query(feedQuery)

By default, Apollo Android offloads I/O work to a background thread and it is safe to call the ApolloClient from the main thread.

  • On the JVM, the whole request runs in a coroutine using Dispatchers.IO by default. You can customize the dispatcher with the dispatcher constructor parameter of ApolloClient
  • On native, the request offloads the cache and network I/O to background threads that resume in the main dispatch queue. For this reason, the ApolloClient APIs assume they are called from the main thread. It's not possible to customize the dispatcher but cache and network I/O are not done on the main thread.

Cancellation is handled through the CoroutineScope. Cancelling the current scope will cancel any ongoing request.

Because it is safe to call the ApolloClient from the main thread, the result will also be dispatch to the main thread and you can direcly use the response to update your data.

Strongly typed query results

Query results are defined as immutable classes that at each level only contain the properties defined in the corresponding part of the query definition. This means the type system won't allow you to access fields that are not actually fetched by the query, even if they are part of the schema.

In other words, Apollo Android generates classes based on the queries you write, not based on the schema.

For example, given the following schema:

enum Episode { NEWHOPE, EMPIRE, JEDI }

interface Character {
  id: String!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
}

And the following query:

query HeroAndFriendsNames {
  hero {
    name
    friends {
      id
      name
    }
  }
}

Apollo Android generates a typesafe model looking like this (details are omitted to focus on the class structure):

class HeroAndFriendsNamesQuery {
  data class Data(val hero: Hero)
  data class Hero(val name: String, friends: List<Friend>)
  data class Friend(val id: String, val name: String)
}

Because the above query doesn't fetch appearsIn, this property is not part of the returned result type and cannot be accessed here. Similarly, id is only accessible in Friend and not Hero.

Because GraphQL supports nullability, you have compiled-time type safety. If the request is successful, all the queried data will be accessible and only this data. There is no need to handle null fields in UI code.

Edit on GitHub