When we hear about GraphQL, it’s often mentioned as the new way to retrieve data from the server. The silver bullet that will replace REST APIs. This is true, GraphQL can do an amazing job to run the new generation of server APIs but this is not the whole picture.
From the homepage of the official website, GraphQL is described as “A query language for your API” where you:
- First, describe your data
- Then, ask for what you want
- Finally, obtain predictable results
Many Tools have been developed to ease the use of GraphQL server-side: From Relay, Apollo Data Tools, express-graphql etc… but few people focused on using it on the client. While you’ll probably get the most of it, if it’s used server-side, using GraphQL on the client can be valuable as well and often, using GraphQL on the server requires a big investment where you probably have to rewrite your entire application to make the transition.
A typical React/Redux application
In the React Ecosystem, a large number of applications are using Redux to store their data in a global state tree. How can we use GraphQL to improve the architecture of such applications without rewriting our application from scratch?
So first, let’s try to take a look at a typical React/Redux Application (A Todo Application of course). We’ll probably have:
- A reducer that “stores” the data in the global state:
- An action creator used to retrieve todos from the server:
In most cases, This action creator will rely on
redux-thunk to trigger a network request and dispatch the action once the results retrieved.
- A selector
getTodosresponsible of retrieving the
todosfrom the global state
And to link all of these items together, we would use
react-redux to bring our data and action creators to our component. A complete
TodoList React Component could look like that:
Declarative data fetching
Let’s take a deeper look at this component. It has three responsibilities:
- It triggers an action creator to fetch Data
- It uses a selector to retrieve Data from the redux tree
- And it renders the Data
React’s main purpose is providing a declarative API, to express how your data get transformed into DOM elements, but in our example above, the fetching and data retrieval is imperative. This means it’s the responsibility of the persons who write the component to trigger the data fetching requests and eventually handles data refreshing. And in this area, Relay has been doing a great job to transform these imperative calls into a declarative API. What if we could provide a declarative API (similar to Relay) without the need of rewriting our APIs to use GraphQL? and without even using Relay?
We want our component to be written like this:
If we need more data such as the authenticated user, our query could be:
Basically, we use a Higher Order Component called
query to declare that our component needs a list of todos, and for each todo, we want its id, text, and done attributes. We don’t mind how this data is fetched from the server or retrieved from the redux store, we just declare what data the component needs and it will be made available as a prop.
How is this possible?
Ok! this sounds awesome right! but isn’t this too difficult to achieve, how do we match each part of this query to its corresponding actions / selectors?
We need a tree resolution algorithm where we match each node of the tree to a function that fetches and retrieves this data. And you know!! this is exactly the purpose of GraphQL. A way to match a
Ok! Let’s setup GraphQL to resolve the query above:
The idea here is for every node of our query, we write:
1- A schema: A good side effect of using GraphQL is the schema which will be used to validate our data. This ensures a valid data is provided to all your React Components.
2- A resolver: A function with the following shape:
Make our GraphQL resolvers available for the query HoC
Now that our GraphQL setup is ready, we can make it available on the React context, that way the
query HoC can use it to provide data to the wrapped components. This is the exact same technique used by
react-redux to make the store available for connected components.
Now, you are ready to go! wrap your components with
Is this worth it?
If you’re working on a small application with dozen of actions and selectors, probably not. Just stick with the imperative fetching, but If your application is big enough, I would say, this is certainly worth a try.
I already mentioned the fact that using GraphQL allows you to validate your data, you are certain that the data provided to your components would always be valid against the defined schema.
Another good side effect is the possibility to use GraphiQL. If you’re not familiar with it yet, it’s a web interface which allows you to test your GraphQL queries before using them in your components. Also, it allows you to navigate through your data which increases data discoverability a lot. You won’t lose your time looking or rewriting existing redux selectors, if the data is already available, you’ll just find it in GraphiQL.
You can find the
query HoC and the
GraphProvider in this library, but it’s easy enough to write on your own if you prefer to.
Who is using this approach already?
Me:). I don’t know if anyone else is but we’re considering using it for Calypso, the new WordPress.com front-end. Here is the PR
Time to get your hands dirty! and let me know if you have any thoughts or concerns on this 🙂