Explore GraphQL with Apollo & React: Build a Superhero Database

Curious about all the buzz surrounding GraphQL, but not quite sure why you should be excited? You’re in the right place! We’ll shed some light on what GraphQL is and give you an opportunity for some hands-on experience.
Let’s start by clearing the air and answering the $20,000 question: what is GraphQL? No, it’s not an obscure function on your TI-89. It’s a query language at heart — or query specification more accurately — that can be used to fetch data from just about any data source.
Better yet, it allows you to fetch the exact data you need — no more, no less — in a single network request. While that may not sound like the sexiest tech to come out of the Facebook factory of innovation, you may just find yourself pleasantly surprised at how useful it can be.
All that’s needed is an Apollo server to act as our endpoint and a React app using the Apollo client to leverage any data within. We’ll tackle the server first.
Key Takeaways
- GraphQL is a query language that allows for fetching precise data in a single network request from any data source, providing a more efficient and flexible alternative to traditional REST APIs.
- Apollo server and React app using the Apollo client are needed to leverage data within GraphQL; the server acts as the endpoint and the client fetches the data.
- The process of creating a GraphQL schema, adding data, defining resolvers, and putting it all together is demonstrated with a superhero database example.
- The tutorial also demonstrates how to integrate these queries with a React app, showing how back-end developers and front-end developers can work almost independently with the schema acting as a middle man.
Getting Started with Apollo Server
To get our Apollo server started, create a folder called apollo-server
in your favorite working directory. Next, enter that directory and run the following npm
command — you do have npm and Node installed, right? — to get the Apollo framework in place:
npm install apollo-server apollo-server-express graphql
Now that you’ve got the various bits and pieces of the Apollo server in place, it’s time to actually tell our server what to serve. Go ahead and create an empty index.js
file in the apollo-server
directory and add the following to it:
const { ApolloServer, gql } = require('apollo-server');
This line simply pulls in the required objects for starting an Apollo server and parsing our query strings into query documents for GraphQL.
Our First GraphQL Schema
Next up, let’s add our first schema:
// This will be our GraphQL schema
const typeDefs = gql`
type User {
id: ID!
name: String
superpowers: [Superpower]!
}
type Superpower {
id: ID!
text: String
}
type Query {
users: [User]
user(id: ID!): User
}
`;
Here we add our type definitions. The first is of type User
which we define as an object having an id
, name
, and superpowers
field. The second is a simple id
and text
to describe each superpower. Finally, the third defines two acceptable queries — users
and user
— that, respectively, return all users or a single user that matches the provided id
argument.
Pretty easy, right?
Adding a Dash of Data
Next, let’s add some mock data to bring our schema to life:
// This will be our mock data to query
const users = [{
id: '1',
name: 'Peter Parker',
superpowers: [{
id: '1',
text: 'Web slinging'
},{
id: '2',
text: 'Spidey sense'
}]
},{
id: '2',
name: 'Tony Stark',
superpowers: [{
id: '3',
text: 'Industrial design'
},{
id: '4',
text: 'Robotic fashion'
}]
}];
All we’re doing here is adding two users to our mock data. It’s worth pointing out that GraphQL isn’t relegated to only querying JavaScript arrays. This could be any database or other data construct. We’re just keeping things simple here to focus on the task at hand.
Don’t Forget Resolvers
Next up, we need to tell GraphQL how to interpret the queries we defined above. This is done with resolvers:
// This will be a map of functions to return the data described by our schema
const resolvers = {
Query: {
users: () => {
return users
},
user: (root, { id }) => {
return users.find(user => user.id === id);
},
},
};
You’ll notice the first query users
requires no arguments and returns the entire users list (at least in theory, more on that later). The second query user
accepts the ID of the user to be fetched and returns said user.
Putting It All Together
To finish off our Apollo server, we just need to instantiate a new instance and start listening for connections:
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({ url }) => {
console.log(`Apollo server started at ${url}`)
});
Here we send the ApolloServer
constructor our schema and resolvers created above. All that’s needed then is to actually start the server, but first, here’s what your index.js
should look like:
const { ApolloServer, gql } = require('apollo-server');
// This will be our GraphQL schema
const typeDefs = gql`
type User {
id: ID!
name: String
superpowers: [Superpower]!
}
type Superpower {
id: ID!
text: String
}
type Query {
users: [User]
user(id: ID!): User
}
`;
// This will be our mock data to query
const users = [{
id: '1',
name: 'Peter Parker',
superpowers: [{
id: '1',
text: 'Web slinging'
},{
id: '2',
text: 'Spidey sense'
}]
},{
id: '2',
name: 'Tony Stark',
superpowers: [{
id: '3',
text: 'Industrial design'
},{
id: '4',
text: 'Robotic fashion'
}]
}];
// This will be a map of functions to return the data described by our schema
const resolvers = {
Query: {
users: () => {
return users
},
user: (root, { id }) => {
return users.find(user => user.id === id);
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({ url }) => {
console.log(`Apollo server started at ${url}`)
});
Go ahead and fire it up with node index.js
and visit http://localhost:4000/
to see the fruit of your labor!
You should be greeted with a GraphQL playground that lets you try out interactive queries against the schema you’ve created.
Going Hands-on
Let’s test it out by entering this query in the left-hand pane:
query {
user(id: 1) {
name
}
}
Here we use the user
query we just set up, and pass it the id
of 1. We’re also telling GraphQL that we only want to return the name
of said user. The result in the left hand pane — after clicking the play-like button — should look like this:
{
"data": {
"user": {
"name": "Peter Parker"
}
}
}
Let’s say you want to take a peek at his superpowers too. All you have to do is request that field:
query {
user(id: 1) {
name,
superpowers {
text
}
}
}
We added the superpowers
field and, since we only care about the text and not the superpower ID, we specify as much. The result should now display each superpower for our first user:
{
"data": {
"user": {
"name": "Peter Parker",
"superpowers": [
{
"text": "Web slinging"
},
{
"text": "Spidey sense"
}
]
}
}
}
Say we want to grab all users and their superpowers, we can rely on the users
query we defined:
query {
users {
id,
name,
superpowers {
text
}
}
}
And the result:
{
"data": {
"users": [
{
"id": "1",
"name": "Peter Parker",
"superpowers": [
{
"text": "Web slinging"
},
{
"text": "Spidey sense"
}
]
},
{
"id": "2",
"name": "Tony Stark",
"superpowers": [
{
"text": "Industrial design"
},
{
"text": "Robotic fashion"
}
]
}
]
}
}
Only care about superpowers? We can do that too:
query {
users {
superpowers {
text
}
}
}
And you get:
{
"data": {
"users": [
{
"superpowers": [
{
"text": "Web slinging"
},
{
"text": "Spidey sense"
}
]
},
{
"superpowers": [
{
"text": "Industrial design"
},
{
"text": "Robotic fashion"
}
]
}
]
}
}
At this point you should be able to appreciate the supreme flexibility and allure of GraphQL. With a single query and connection we can retrieve any slice of the data we desire. All that’s necessary is a well designed schema and the resolvers to support it.
Even better, back-end developers and front-end developers can do their thing almost independently. With the schema acting as a middle man, both groups can effectively avoid stepping on each other’s toes. And really, that’s GraphQL in a nutshell. Before we wrap this tutorial up however, let’s take a look at how to integrate these queries with an actual React app.
Introducing React to the Mix
Go back to your root working directory and run the following commands to set up a bootstrapped React app with the requisite GraphQL and Apollo libraries:
npm install -g create-react-app
create-react-app my-graphql
cd my-graphql
npm install apollo-boost react-apollo graphql
Next, replace the contents of src/index.js
with the following:
index.js:
import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'
import App from './App'
const client = new ApolloClient({
link: new HttpLink({ uri: 'http://localhost:4000/graphql' }),
cache: new InMemoryCache()
})
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
)
All we need here are the usual imports for a React app along with the Apollo client to interface with our new Apollo server. To create the Apollo client we just need a link to the server http://localhost:4000/graphql
and a way to cache our goods. With that, we simply render the app.
Next, we need to set up the app to query and display the data presented by our Apollo server. Go ahead and replace the default src/App.js
with this:
App.js:
import React from 'react'
import { Query } from 'react-apollo'
import { gql } from 'apollo-boost'
const TEST_QUERY = gql`
{
user(id: 1) {
id,
name,
superpowers {
text
}
}}
`;
const App = () => (
<Query query={TEST_QUERY}>
{({ data: { user }, loading }) => {
if (loading || !user) {
return <div>Loading ...</div>;
}
return (
<p>
{user.name} ({user.id}) has the following superpowers:
<ul>
{user.superpowers.map(superpower => (
<li>
{superpower.text}
</li>
))}
</ul>
</p>
);
}}
</Query>
);
export default App
You should see some familiar patterns here. We first use gql
to create a GraphQL query document that requests the user with ID 1 — more specifically, their ID, name and superpowers text. Then we pass the document to our server with the Query
tag. It’s here that we can format the results in a pretty React app.
Go ahead and start the server with npm start
and check out the beautiful results at http://localhost:3000/
.
And with that, our tutorial is complete. You’ve created an Apollo server and fed it some simple data structures. You discovered how to write schemas and resolvers to define interactions with the data. You then practiced querying specific pieces of that data. Finally, you tied it all together with a React app that retrieves data from the server and presents it in a nicely formatted way.
While this should be enough to get you started with integrating GraphQL in your future projects, there’s lots still to learn. Mutations for adding and changing data is a great next step.
Hope you enjoyed this tutorial — happy coding!
FAQs about GraphQL
GraphQL is a query language for APIs and a runtime for executing those queries with your existing data. It was developed by Facebook and provides a more efficient and flexible alternative to traditional REST APIs.
While REST relies on multiple endpoints to retrieve specific data, GraphQL allows clients to request only the data they need in a single query, reducing over-fetching and under-fetching issues.
Some key features of GraphQL include a hierarchical structure for queries, a strong typing system, real-time data with subscriptions, and introspection, which allows clients to query the schema itself.
A GraphQL schema defines the types and relationships of data available in the API. It serves as a contract between the client and the server, specifying the structure of valid queries and mutations.
Queries in GraphQL are hierarchical and mirror the shape of the response data. Clients can request specific fields on types and nest them to get the desired data structure in the response.
Resolvers are functions that define how to retrieve or mutate data for a specific field in the schema. They are responsible for fetching the actual data from the data source.
Growing up with a love for coding, I’ve greatly enjoyed learning many forms of programming, especially web development. This has lead me to professional success ranging from the creation of cutting edge, web based, healthcare applications to simple CMS frameworks.
Published in
·Docker·Open Source·Programming·Software Development·Web·Web Hosting & Domains·January 15, 2016