In my last post I took a closer look at how the Apollo iOS GraphQL client executes queries and what the resulting JSON looks like. In this post I’m going to focus on how the JSON is parsed and converted to the native Swift types generated by the apollo-codegen tool and also look at how the Apollo iOS client caches results.
Parsing the JSON
The JSON parsing is pretty straightforward and is handled by the iOS JSONSerialization APIs, with the result being a Dictionary of [String : JSONValue], where a JSONValue is simply a typealias to Any. If this succeeds, a GraphQLResponse instance is created with the result.
The GraphQLResponse class contains a parseResult() method which is called from the completion handler of the original network operation which starts the conversion and caching processes.
Converting to Native Types
The process of converting the raw JSON to the native Swift types generated by the apollo-codegen tool takes is handled by the GraphQLResultReader class and its delegate, in this case the GraphQLResultNormalizer class. This in turn creates a GraphQLResult instance containing the native Swift objects and a RecordSet instance which is shared with the ApolloStore class, which acts as the cache.
The ApolloStore class manages a RecordSet, which is a “set of cache” records which basically amounts to a dictionary mapping CacheKey to Records where a CacheKey is simply a String and a Record is a struct containing a copy of the CacheKey along with the JSON to cache. The records are created during the conversion process to native types and cache keys are generated for each record at the same time.
When a query is made, depending on the cache policy set, the ApolloStore class and underlying cache is first queried in the hope of fetching cached results. If results aren’t found within the cache, the original network request proceeds.
The ApolloStore class also plays a role in query watching. When making a query you also have the option to watch a query for changes, and respond to those changes. When calling watch instead fetch when making a query the GraphQLQueryWatcher class is used and it registers itself as a subscriber with the ApolloStore class so that when related changes are made the underlying query is re-executed, returning cached data if possible or the latest data from the server if not.
Since the 0.5.6 release that I’ve relied on for this set of posts the Apollo iOS developers have been refactoring and reworking the query execution model and cache, so in the latest code you’ll likely find some changes. It should be interesting to see going forwards to see what new features are added to the client and if GraphQL use in iOS apps picks up or not.