Apollo – The GraphQL client that makes API integration a breeze
Integrating apps and servers is not an easy task, we all know that. Even with great tools like Alamofire and Retrofit there are still a lot of things to take care of in the app side: different endpoints, encoding / decoding JSON strings, API versions, data consistency and so on…
Recently I have worked in a project with server integration and we had the opportunity to choose new technologies to work with and to try to avoid some of these problems. The choice was a GraphQL server and in the app side the Apollo framework.
Why GraphQL?
GraphQL is a query language created by Facebook that is being used in its apps since 2012. The reasons why we chose to use it are:
Flexibility: The client decides which data should be available in the result. This avoids unused data in the server response.
Based on a schema: There is a well defined data model available, so the client knows exactly how this data will be returned and how to perform the queries.
Easy to learn: The query language is very similar to JSON, so it’s syntax is easy to understand.
API Documentation: Since GraphQL exposes a schema to the clients, it’s easy to create documentation and make query validation to avoid mistakes when fetching data. There are a lot of IDEs that help to create queries and explore available data.
Can be implemented in any language: GraphQL is available for many different languages and can work beside REST with no problem, it’s basically another way to expose data. It also works with any database and it’s up to the developer to decide what is available in the schema and what is not.
Mutations: GraphQL provides a nice and well structured way to perform data updates in server.
Open Source: GraphQL has a big community working on it. More about GraphQL can be found in the official documentation.
Here is a small example of a GraphQL query:
query GetPostById {
Post(id: "cj6py4hi614bx01580y11k0go") {
title
content
}
}
And its response:
{
"data": {
"Post": {
"title": "International Space Station",
"content": "Its first component launched into orbit in 1998."
}
}
}
Why Apollo?
On the client side, there are different situations that the application has to deal with. However, since GraphQL runs over an HTTP connection and its response is a JSON string, the problems are pretty much the same as REST. But actually, here starts all the magic.
Apollo is a very nice framework. It provides everything necessary to create requests to the server. It also lies on a GraphQL server schema to make all the parsing, normalization and caching of data a piece of cake. Here are the main reasons to choose it:
Multiplatform: Apollo is available for many frontend platforms, including native iOS and Android. All these platforms follow the same concepts and have its own language particularities. So you will feel home when using it in your code. Go to this page to get the official documentation for each one.
Based on a schema: Apollo uses the GraphQL schema available in the server to know how data is structured. It allows the parsing to native objects to be automatic and instantaneous.
Normalized Cache: Apollo has its own cache. All data fetched from the server is normalized and stored in a local cache. This helps to keep data consistent and always updated through all the UI.
Fetch policies: You can easily choose between fetching data from Apollo’s cache or reaching the server. This way you might avoid unnecessary requests to server.
Next I will show how simple it is to configure Apollo and how easy it is to make queries and use its cache. Also, you’ll see how it automatically creates typed objects with all data you just fetched.
How Apollo works
For example purposes on this post I will use the iOS version in Swift.
Set up Apollo
Setting up Apollo in a project requires a little configuration, but it’s very simple to do it. For iOS it requires basically the following steps:
Install Apollo via CocoaPods, Carthage or manually
Install Apollo Codegen via npm: This codegen is responsible for generating API.swift file with all structs and queries based on the schema
Set up a build phase: This runs the codegen during build time to create the API.swift file
Download GraphQL schema and add it to the Xcode project: This is the GraphQL server schema conventionally called schema.json, it should be always updated with server version
Build the project
Add the generated API.swift file to the Xcode project: You can git ignore this file. It will be generated every time you build the project.
This is the initial setup to start making queries and mutations on your iOS app. All the setup steps are detailed in Apollo documentation.
Start performing fetches and mutations
With everything up and running we can start performing fetches. To do that you simply create GraphQL queries in a .graphql file. You can create as many files as you want. For this example I will be using a very simple API with posts and comments. There is a link for the sample project in the end of this post.
Ok, now let’s see what Apollo can do!
First of all we create a .graphql file with the GraphQL query to fetch all posts:
query AllPosts { allPosts { ...Post }}
fragment PostObject on Post { title content}
If you build the project now you will see that API.swift file have now a bunch of code. In this code there are swift methods to perform the queries and structs that represent the data returned by the server.
The last thing we need before performing a fetch query is the client that accesses the server. To do this we create an instance of Apollo Client. I use a singleton with a unique apollo client to keep a unique cache and use in all code. But let’s keep it simple for now.
let url = "https://my-amazing-api.com/graphql"let apolloClient = ApolloClient(url: url)
Now we use the auto generated query object as parameter to the fetch method in the client and a callback to deal with the result. This result will already be cached.
apolloClient.fetch(query: query) { result, error in let posts: [PostObject]? = result?.data?.allPosts.map { return $0.fragments.postObject } self.posts = posts ?? []}
As you can see in the .graphql file I used a fragment called PostObject. Apollo converts this fragment into a struct. The response from server will be mapped into this structs and you can use them directly in your UI code and other parts of the project.
You can also pass to the fetch method a parameter to change the cache policy. There are currently four options:
returnCacheDataElseFetch: Return data from the cache if available, else fetch results from the server
fetchIgnoringCacheData: Always fetch results from the server
returnCacheDataDontFetch: Return data from the cache if available, else return nil
returnCacheDataAndFetch: Return data from the cache if available, and always fetch results from the server
Using these options appropriately can reduce access to network and improve UI response. In the sample project for example I fetch all posts in the list screen. And in the details screen I just used the cached data, so I avoid another request and I guarantee that my fetched data always come from the same place, avoiding inconsistency in the app.
Conclusion
This is just a small example of what Apollo can do. In the sample project there are also examples of watching queries that helps us to keep UI always updated with the last cache version and also a mutation to perform changes in server data.
My experience with Apollo started with a few concerns regarding this whole new concept of fetching and manipulating data along with the server. But after a few months using it I can say that I would always choose Apollo for my future projects.
The Apollo project is new and there are already a lot of users. There are a lot of things to come and you can, of course, contribute as its open source. You can check the example code in this GitHub repository.
I’m a mobile developer who loves giving life to smart and beautiful apps. I also appreciate a good walk at the beach, cold beer, burger and fries, good music and talk about life, the universe and everything else.