GraphQL is becoming the new standard for data-driven applications. It is an open-source data query and manipulation language for APIs, and a revolutionary way of thinking about communication between our client and the server.
GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
After being made publicly available by Facebook in 2015, it has since become a strong alternative to the REST API architecture.
To start using GraphQL in your React application, you’ll need to understand the following terminologies:
A GraphQL query is similar to a GET
request in the REST
API architecture. Queries are used to fetch or retrieve data from a GraphQL server. They are what determines the structure of our received data; this means that, as a user, you can request exactly what you want and how you want it structured. GraphQL queries are usually enclosed in braces:
{ query_fields }
The query fields are keys that reference specific data on our server. These data have types like string, int, float, Boolean, ID, or object. Here’s an example of a GraphQL query and its corresponding result:
// query { article(slug: "5-amazing-math-tricks-flyingturtle") { title description author { name country } } } // result { "data": { "article": { "title": "5 Amazing Math Tricks", "description": "here's what no one told you", "author": { "name": "Flying Turtle", "country": "Nigeria" } } } }
In our example, notice how the result has the same structure as the query. If we had placed the description
before the title
in our query, we’ll get our result in the same order. The parenthesis after article
on line 3 of our first block is what houses the query params. For this query, we provided the article slug as the unique identifier for the particular article we need from our GraphQL server.
It is also important to note that on line 6 of our first block, the author
field has an Object
type. When this is the case, we’ll also need to specify the fields we want from the object — in this case, name
and country
.
When comparing GraphQL mutations to the REST API architecture, they are similar to PUT
, PATCH
, POST
, and DELETE
methods. A mutation, just like its name suggests, is a request that modifies the data on our GraphQL server. It can be used to update, insert, or delete data.
The syntax for mutations in GraphQL is similar to that of the fetch
query, only that this time, we’ll add the mutation
keyword before our first opening curly brace, and then pass in the fields we want to mutate and their values as parameters:
// mutation mutation { updateArticle(slug: "5-amazing-math-tricks-flyingturtle", title: "just right") { title description author { name country } } } // result { "data": { "article": { "title": "just right", "description": "here's what no one told you", "author": { "name": "Flying Turtle", "country": "Nigeria" } } } }
If you noticed, we also specified the return values in our mutation request. This tells the GraphQL server exactly what to return to us after carrying out our request.
GraphQL clients enable us to send API requests to our GraphQL server. An example of a GraphQL client is curl
from our command line:
curl -X POST \ -H "Content-Type: application/json" \ -d '{"query": "graphql_query"}' \ url_to_graphql_server
We can also use the JavaScript fetch
API for making API calls to our GraphQL server:
fetch('url_to_graphql_server', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({query: "graphql_query"}) }) .then(res => res.json()) .then(data => console.log({ data }));
These methods look straightforward, but they could get complicated and might require a ton of avoidable code when we start dealing with more complex queries, state management, and caching.
Fortunately, there are more robust GraphQL clients like Apollo and Relay that are built to handle complex queries, caching, and effective state management in our React applications.
Here’s how the Apollo Client documentation describes Apollo:
Apollo Client is a complete state management library for JavaScript apps. Simply write a GraphQL query, and Apollo Client will take care of requesting and caching your data, as well as updating your UI.
The best way to understand GraphQL is by using it. Let’s learn how to use GraphQL with React by building a demo app that uses the Apollo Client to consume a GraphQL article API.
We’ll start by using create-react-app to bootstrap a new React application. If you don’t have create-react-app installed, on your terminal, run:
npm i -g create-react-app
Next:
create-react-app react_graphql
This will bootstrap a React application in a new directory named react_graphql
. To start our application, we’ll navigate to our new directory from our terminal and run npm start
:
cd react_graphql npm start
If you’ve done everything right, a page like this should open in your browser:
To get started with GraphQL in React, we’ll need to install the following packages:
graphql
apollo-boost
, which sets up our Apollo Clientreact-apollo
, which includes the ApolloProvider
component for providing an ApolloClient
instance to our GraphQL componentsLet’s run the following command on our terminal:
npm i -s graphql apollo-boost react-apollo
This should install the packages in our application and add them to our project’s dependency.
Next, we’ll set up our application to process GraphQL queries from our root index file. In our /src/index.js
file, we’ll start by importing ApolloClient
and ApolloProvider
from the apollo-boost
and react-apollo
packages, respectively. Let’s replace what we currently have in the /src/index.js
file with the following code block:
// src/index.js import React from 'react'; import ReactDOM from 'react-dom'; import ApolloClient from 'apollo-boost'; import { ApolloProvider } from 'react-apollo'; import App from './App';
Next, we’ll set up our GraphQL client. To do this, we’ll create an instance of the ApolloClient
and pass in a uri
property. This is where we’ll be providing our GraphQL endpoint:
// src/index.js ... const client = new ApolloClient({ uri: 'https://awesome-node-graphql.herokuapp.com/graphql' })
For the purpose of this article, I’ve built a GraphQL server with Node and Express.js (here’s a link to the GitHub repo). We’ll be able to get data for our article app by sending a query to the GraphQL API.
Now that we’ve set up our GraphQL client, let’s connect it to our React application. We’ll do this by wrapping our App
component in the ApolloProvider
we imported earlier and then supplying our provider with a client
prop:
ReactDOM.render( <ApolloProvider client={client}> <App /> </ApolloProvider>, document.getElementById('root') );
Our /src/index.js
file should now look like this:
import React from 'react'; import ReactDOM from 'react-dom'; import ApolloClient from 'apollo-boost'; import { ApolloProvider } from 'react-apollo'; import App from './App'; const client = new ApolloClient({ uri: 'https://awesome-node-graphql.herokuapp.com/graphql' }) ReactDOM.render( <ApolloProvider client={client}> <App /> </ApolloProvider>, document.getElementById('root') );
Next, we’ll use the Query
component from react-apollo
to consume our GraphQL endpoint. When calling the Query
component, we’ll pass in our GraphQL query as its prop. First, let’s replace what we currently have in our /src/App.js
with the following code block:
// src/App.js import React from 'react'; import { Query } from 'react-apollo'; import { gql } from 'apollo-boost';
Here, we’ve imported the Query
component from react-apollo
and gql
from apollo-boost
. The gql
template literal tag parses GraphQL query strings into the standard GraphQL abstract syntax tree. Let’s declare a variable, getAllArticles
, and assign it our GraphQL query:
// src/App.js ... const getAllArticles = gql`{ articles { title description coverImageUrl author { name country } } }`
Next, we’ll create our App
component and, in it, call the Query
component from react-apollo
. The Query
component uses React’s render prop pattern and returns an object from the Apollo client containing the following properties:
loading
: Returns a Boolean value based on the request statuserror
: Returns an error message if our request is unsuccessfuldata
: Returns the requested data from our serverLet’s add the following block to our src/App.js
file:
// src/App.js ... const App = () => { return ( <> <Query query={getAllArticles}> {({ loading, error, data }) => { if (loading) return <p>Relax, it's worth the wait...</p> if (error) return <p>Looks like we've got a problem...</p> }} </Query> </> ); }
To populate our page with the fetched data, we’ll use the JavaScript map
function to iterate our data. Our final /src/App.js
file should look like this:
import React from 'react'; import { Query } from 'react-apollo'; import { gql } from 'apollo-boost'; const getAllArticles = gql`{ articles { title description coverImageUrl author { name country } } }` const App = () => { return ( <Query query={getAllArticles}> {({ loading, error, data }) => { if (loading) return <p>Relax, it's worth the wait...</p> if (error) return <p>Looks like we've got a problem...</p> return ( <div className="container"> <h1>Articles</h1> <div className="row"> {data.articles.map(article => ( <div className="col-sm"> <div className="card" style={{width: "18rem"}}> <img src={article.coverImageUrl} className="card-img-top" style={{height: "10em"}} alt="cover" /> <div className="card-body"> <h5 className="card-title">{article.title}</h5> <p className="card-text">{article.description}</p> <button className="btn btn-primary">Read</button> </div> </div> </div> ))} </div> </div> ) }} </Query> ); } export default App;
Finally, let’s add the Bootstrap CDN to our /public/index.html
file for our app’s CSS styling. We’ll paste the following <link>
tag before the <title>
tag definition:
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
When we start our application and navigate to localhost:3000/
in our browser, we should see a similar page to this:
In this article, we’ve learned the basics of GraphQL and how to use it in our React applications. Of course, GraphQL won’t replace the REST architecture immediately, as it will be difficult to rewrite all the existing platforms overnight, but it eventually will.
GraphQL solves a whole lot of problems for data-driven applications, including the overfetching and underfetching of information. It makes complex queries relatively easy to write and gives clients the power to ask for exactly what they want.
Here’s a link to the GitHub repository for our demo app. Feel free to reach out to me via Twitter if you need any further assistance on GraphQL and React.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowFix sticky positioning issues in CSS, from missing offsets to overflow conflicts in flex, grid, and container height constraints.
From basic syntax and advanced techniques to practical applications and error handling, here’s how to use node-cron.
The Angular tree view can be hard to get right, but once you understand it, it can be quite a powerful visual representation.
In this post, we’ll compare Babel and SWC based on setup, execution, and speed.
2 Replies to "GraphQL + React for noobs"
Thanks for this article, Ebenezer. In recent months I’ve been using axios to make traditional API calls. Now, on a personal project of my own, I’m going to try using GraphQL. Sounds like you’re a proponent of using the Apollo Client? Quick question: With Apollo installed, what do you use for non-local state management? I’ve read that Apollo can be used as as substitute for the Context API and Redux. My recent experience has been with the Context API. I wonder if it makes sense to have an app with both Apollo and the Context API?
Hi Robert, I’m glad you found this helpful. I think to a great extent, choosing a state management tool boils down to personal choice.
In this case, I think using the Apollo cache would be easier. You might want to check out this article on Managing Local State with Apollo Client and React Hooks: https://itnext.io/managing-local-state-with-apollo-client-and-react-hooks-9ad357e6d649
I also have an article on React Hooks and the Context API where I tried making the UseContext setup as straightforward as I can: https://blog.logrocket.com/use-hooks-and-context-not-react-and-redux/