Introducing the Apollo Android GraphQL client
Mike Nakhimovich
The entirety of my Android career has been spent hitting RESTful APIs. No matter the app, the general setup was the same: Using get/post/delete with a predefined set of endpoints in a RESTful api. Recently, The New York Times started looking at other ways to transfer data between our servers and clients. One of our current problems is that we have a team dedicated to creating templates and endpoints for all of our mobile clients on Android and iOS. As a result, we had quite a few permutations of data feeds to manage, including: Android tablet, Android phone, iOS phone, etc. This meant that any time we wanted to request a different set of data, like new language for an article, we had to wait for one of our teams to make another template and endpoint. As you can imagine, this became inefficient.
Ideally, we needed a way for each client to request or query the data that they need without having to change anything on the server. If one Android phone needs small crops of images while another Android phone needs large crops, we should be able to use the same article API to fulfill the request. Of course, a single variation between different requests can be accomplished with request params but that didn’t quite fit our use case. We request up to 200 fields for any given article. 90% of the fields are not required for all articles, and a third of them have some special configuration. It would be nice to get only the necessary fields on a per request basis.
Choosing GraphQL
It became clear that REST is not the right tool for the job. We dug around for other options and landed on the GraphQL spec created by Facebook. For those that are unfamiliar, GraphQL is a query language for domain driven requests from a client to a server. Here’s a simple example from the front page of graphql.org:
Describe your data by making a schema:
type Project { name: String tagline: String contributors: [User] }
Ask for what you want by writing a query:
{ project(name: "GraphQL") { tagline } }
Get predictable results:
{ "project": { "tagline": "A query language for APIs" } }
The way that GraphQL works is that you have a pre-defined schema of all the things a client can request. Then, clients can make a query which asks for only the fields that they need. The query is posted to a server which executes that query, pulling from any backends or databases to retrieve exactly the data the client asked for.
So a query like {a, b, c} returns {a: 1, b: 2, c: 3}. Or, you can query {a, c} and get back only {a: 1, c: 3}. This seemed perfect for us, and there was only one problem – there didn’t seem to be any clients for Android. After trying to create our own implementation internally, we realized why one didn’t exist yet: The GraphQL specification has a lot of things to implement, including fragments, union types, mutations, custom fields, nullable types, etc. Working in a statically typed language where reflection is expensive did not make anything easier.
Working with the community
Rather than creating something internally, we felt that the community as a whole would benefit from an open source GraphQL client. So we looked around for anyone else that might have the same needs. Through an Android Slack, I was connected with Felipe Lima from Airbnb who told me about Apollo GraphQL, a rather robust client implementation, first in JavaScript and recently also in Swift for iOS. He said that he had worked a bit with them trying to bootstrap an Android version together. We ended up taking a call, and tried to figure out what direction to go to start working on a GraphQL client for Android. After looking around a bit more we found another partner, Shopify, who had a developer also interested in creating an Apollo Android client. The base contributor team had been formed.
Five months, 200+ commits, and 13 contributors later, we have released version 0.30, which is the first version ready for public consumption. While there might be a few minor API changes we are feature complete for 1.0.
What is Apollo Android?
Apollo Android is a GraphQL compliant client library that generates Java models from standard GraphQL queries. These models give you a typesafe API to work with GraphQL servers. Apollo will help you keep your GraphQL query statements together, organized, and easy to access from Java. Here are some of the features you get:
Code generation: You can just change a query and recompile your project, and Apollo codegen will rebuild your data model. Code generation also allows Apollo to read and unmarshal responses from the network without the need of any reflection (see the README for an example).
Network calls and caching: Apollo-Android also includes a runtime to execute queries and cache the results. The client can be configured with three levels of caching:
- HTTP response cache: This stores raw HTTP responses.
- Normalized disk cache: This does per-node caching of results in SQL.
- Normalized in memory: This is an optimized Guava in-memory cache.
RxJava: We have included RxJava wrappers to work with RxJava 1 and RxJava 2.
Optionals: Optional support is here as well. We work with Guava Optionals, Java optionals or our own shaded version. We are 100% ProGuard compatible with no configuration.
Trying Apollo Android in your app
Check out the example in the README. The majority of your interactions will look something like:
Step 1: Add a query to your project:
query FeedQuery($type: FeedType!, $limit: Int!) { feed(type: $type, limit: $limit) { comments { id } postedBy { login } } }
Step 2: Compile your project to get generated code for the query.
Step 3: Interact with the generated type safe QueryBuilder and response:
apolloClient.newCall(FeedQuery.builder() .limit(10) .type(FeedType.HOT) .build()) .enqueue(new ApolloCall.Callback<FeedQuery.Data>(){ public void onResponse(Response<FeedQuery.Data> response) {} public void onFailure(@Nonnull Throwable t) {} });
or the RxJava version
Rx2Apollo.from(apolloClient .newCall(FeedQuery .builder() .limit(10) .type(FeedType.HOT) .build())) .subscribe()
You can also find a sample project in the repository on GitHub.
Conclusion and thanks
We believe we made this library simple yet powerful. A developer can go from writing a GraphQL query to being up and running in a manner of minutes. We’d love to hear from you on how to make Apollo-Android better, and we’re currently working on a roadmap of features for the coming months.
It was incredible to work with talented developers from various companies to create an open source project. I’d like to recognize the main contributors on the project:
- Ivan Savytskyi, who was by far the top contributor, main developer of the code generation through a few rewrites, and generally an awesome guy. This project would not be a reality without the insane amounts of time he put in.
- Felipe Lima for getting the project off the ground.
- Ben Schwab for implementing the caching layer and countless other things.
- Martijn Walraven from the Apollo team for offering us guidance, check out his iOS library here.
- Marwan Ahmed for creating the Gradle plugin to run our code generation.
- Vishesh Vadhera for giving a big helping hand in documentation.
Learn more about the project and contribute on our GitHub repository!