Native code generation at Facebook
A talk by Hyo Jeong at the August 2016 GraphQL San Francisco meetup
We recently hosted the second GraphQL SF meetup, “GraphQL in production”. This is a recap of just one of the talks, check them all out on YouTube!
Today, we’re going to do a summary of part of Hyo Jeong’s talk about GraphQL developer tools at Facebook. As the originators of GraphQL, Facebook’s engineers have been using GraphQL since 2012, and have had a lot of time to think about the kinds of tools that are valuable to their organization. Hyo works on some of these developer tools and most notably GraphiQL, everyone’s favorite GraphQL query IDE.
This talk especially spoke to me because it was a great overview of the kinds of productivity-enhancing tools the community can build on top of GraphQL, and a great look into Facebook’s internal process. The following is a recap the part of his talk that focused on native code generation. Watch the full talk here, or at the end of this post!
GraphQL: A Solution to a Facebook-Sized Problem
To start off, Hyo briefly introduced the audience to GraphQL. It’s a query language Facebook uses to power all of its mobile applications. One of the most important parts of GraphQL is the schema — a type system that defines the data you can fetch from a specific GraphQL server.
The type system is useful as documentation of the data you can fetch, but it has another, even more important purpose: it’s a platform you can use to build tools that make life easy for product developers.
At Facebook, GraphQL, and the tools around it, was the solution to particular problems they encountered with their API as they grew and needed to support a diversity of users’ devices.
The first issue was the existence of many different clients. Not only does Facebook have an iOS and Android app, but also different versions of these apps, different form factors — phone vs. tablet — and some other niche clients.
Facebook needed a toolchain that could help all of these clients get the data they need, without having to do specific work on the server for every version of every client.
As you can see in the diagram above, the native code generation tools take a description of the type system and a set of GraphQL queries as an input, and output a set of response models and query requests.
A fun fact about this tooling is that it’s built entirely on top of the open-source JavaScript GraphQL reference implementation that you can get on npm today.
Modeling queries in native code?
So what does this toolchain actually output? It turns out, it’s not easy to come up with the right implementation right away, and the tooling at Facebook went through several iterations of the design before they arrived at the current system they use internally.
First, Hyo put up a sketch of what the simplest code for fetching a GraphQL query might look like:
In this version, you simply make an HTTP request, parse the JSON, and then render with the response.
But, as you can guess, this can get out of hand as the product grows. You need to manually traverse the data, and as more and more developers add fields to the query, you can end up with merge conflicts. So you need some abstraction that factors the query logic out of the rendering code.
You can see that in this version, the query is wrapped in a very thin class, which helps you set the variables on the query and handles the fetching and parsing for you. You simply get a callback for the result. This becomes very helpful, especially when you are reusing queries.
In the diagram above, you can see that the callback receives a MyFriendsQueryResponse — not just an untyped JSON blob. This is one of the ways you can ensure that your query results are used correctly. Let’s move on to find out how this response class could be generated and why you need it.
The first intuition to generate a strongly typed result from the server response would be something like this:
Here we have an example fragment, and since the fragment operates on the User type, it’s reasonable to associate it with a typed User model. Let’s say our server-side type has name, friends, age, pets, and currentCity fields; we would put getters for those fields on our type-based model.
A new approach: Fragment-based models
But there are a few problems with this approach. To highlight these problems, let’s see what a different approach might look like, and compare the pros and cons. The new approach we’ll consider is a fragment-based model.
In this model, instead of representing all of the fields our server-side model has, we look at the fragment and only add the fields we are actually fetching. Our fragment only has name and friends fields, so those are the only fields we put in our fragment model.
So let’s look at the two approaches side-by-side:
For getName and getFriends, these are basically the same. It gets a little interesting when you get the friends, because in the model-based method you actually get a whole new User model for each friend. In the query-based method, you just have a special subfield type.
A big difference between the type-based and fragment-based model approach is that the type model library is global to your application. Every part of your UI and fetching code is referencing the same models. In the fragment approach, each query, fragment, and UI component gets a special model specific to its needs. This might make the fragment-based model more modular and easier to maintain, since you don’t need to worry about an update to one of the models breaking some distant part of the code.
And there’s one more special error situation to mention: you can see that in the type-based model, there is a getPets method, since the server-side type has that field. But we didn’t actually fetch it in the query.
This is a huge plus for fragment-based modeling. Instead of possibly getting a runtime error on a missing field, you can get a compile error right away that reminds you about the missing a field.
To summarize, here’s a table:
The conclusion is that the fragment-based model makes your code more modular, allowing you to easily catch fetching errors at compile time.
Watch the rest of the talk on YouTube
Hyo covered much more than just native code generation in the rest of his talk, including:
- GraphiQL at Facebook, including performance and experimental features
- The GraphQL language service, which will let you get the typeahead and validation features of GraphiQL, directly in your own editor!
See the whole talk from the top:
One of the reasons I’m extra stoked about this talk is because we’re working on an open-source implementation of this toolset as part of Apollo-iOS. This implementation uses the fragment-based model above, and is based on conversations with the GraphQL team at Facebook and information from talks like this one. Read about it in our introduction post from yesterday:
Follow our publication here on Medium to hear more about how to use GraphQL in your iOS app.
To hear more about what the Facebook Open Source team is developing around GraphQL, don’t miss the first-ever GraphQL conference we’re organizing in SF on October 26th! Speakers will include Facebook Open Source, Angular, Apollo, GitHub and more.