March 16, 2017

React + GraphQL Tutorial — The Server

Jonas Helfer

Jonas Helfer

This is the second part of our full-stack tutorial series that will walk you step by step through building an instant messaging app with React and GraphQL.

Note: Even if you haven’t seen Part 1, you can continue reading here. This tutorial is completely independent from the first part, and you don’t need any code or knowledge from Part 1 to complete Part 2!

Last week, in the first part of this series, I walked you through building a simple frontend with React and GraphQL, and showed you some of the reasons why GraphQL is becoming a pretty popular choice among frontend developers.

This week’s section is all about the server, and it will explain everything you need to know to set up a simple Node GraphQL server with easy-to-use open source libraries.

If you don’t want to take the time to set up your own server, make sure to check out the alternative Part 2 from our friends at Graphcool, which shows you how to quickly set up a GraphQL backend on their service.

Without further ado, let’s get started!

Part of the server we’ll write in this tutorial

1. Setting up

We’re going to use Express in this tutorial, because that’s what most people are currently using, but you should be able to follow along even if you’re using hapi or Koa, because the GraphQL part of this tutorial is largely identical.

For starters, let’s clone the tutorial GitHub repo, which has a few resources we’ll need later. If you’ve already done that in Part 1, you can skip this step.

Since this tutorial has lots of sections, we have to check out the right branch to make sure the repo is in the state we want it to be for the start of this one:

git fetch
git checkout t2-start

You should now see a server folder with package.json.babelrc and server.js in it. package.json contains the most basic dependencies we need to get a server running, namely Express and Babel. server.js contains the minimal “Hello World” example of an Express server, which we’re going to build into a GraphQL server in the rest of this tutorial.

To get up and running, install the dependencies and start the server:

cd server
npm install
npm start

If you point your browser at localhost:4000 you should now see the following:

If you see this, your Express server is now up and running…

With the server up and running, we’re ready to dive into the GraphQL part of this tutorial!

2. Writing your GraphQL schema

When building an app from scratch, I always like to start by thinking about the underlying data model. Maybe it’s an old habit from my Rails days, where step one was always to define a relational database schema, but I’ve found it to be a really great way to begin. In GraphQL, we actually have a name for this approach: schema-first development.

Note: If you’ve already written a schema in the first tutorial, you can just copy over that file from the client and skip ahead to the next step.

To write our schema, let’s create a directory called src and add a file called schema.js in it:

mkdir src
cd src
touch schema.js

The schema file, written in the GraphQL schema language, specifies what object types exist in our app, and what fields they have. In addition, it defines the allowed entry points into our API.

// src/schema.js
import {
  makeExecutableSchema,
  addMockFunctionsToSchema, # we'll use this later
} from 'graphql-tools';const typeDefs = `type Channel {
   id: ID!                # "!" denotes a required field
   name: String
}# This type specifies the entry points into our API. In this case
# there is only one - "channels" - which returns a list of channels.
type Query {
   channels: [Channel]    # "[]" means this is a list of channels
}
`;const schema = makeExecutableSchema({ typeDefs });
export { schema };

We’ll add more types to our messaging app in future tutorials, but for now the Channel type and one entry point is all we need.

The last line takes our type definition string and turns it into an executable schema for our server to use. makeExecutableSchema is a function from graphql-tools, which we now need to install

npm install --save graphql-tools

3. Wiring up the schema to the server

Now that we have our schema, we need to wire it up to our Express server. In this tutorial, we’ll use graphql-server-express and graphql-tools for that. graphql-server-express also needs body-parser, so let’s go ahead and install all of that:

npm install --save graphql-server-express body-parser

Next, we’ll import the functions we’re going to use at the top of ourserver.js file:

import { 
  graphqlExpress,
  graphiqlExpress,
} from 'graphql-server-express';
import bodyParser from 'body-parser';

We’ll also need to import the schema we just wrote in the schema.js file:

import { schema } from './src/schema';

We have to do this because the type definitions only describe what types exist in our schema, and they don’t tell the server how to execute queries against it. makeExecutableSchema turns our type definitions into an executable schema, to which we can add custom resolve functions later. Resolve functions are the core piece of GraphQL that tell the server how to resolve each part of a query. But more on that later, let’s finish wiring up our server first!

In order to make our server respond to GraphQL requests, we need to tell Express to pass requests to our graphqlExpress middleware, which executes the queries against the schema. We do this by replacing the current server.get lines with the following:

server.use('/graphql', bodyParser.json(), graphqlExpress({
  schema
}));

To test whether your server is working, open the following URL in your browser: http://localhost:4000/graphql?query={__schema{types{name}}}

This is what it should look like if it’s working

The query we just executed makes use of GraphQL’s built-in introspection capability. Introspection allows to query the server for information about itself: what types exist, what fields they have, how they are related to each other, what interfaces they implement etc. This lets you build some pretty powerful tools, like the amazing interactive query editor called GraphiQL (pronounced “graphical”), which we’re going to set up right now.

4. Setting up GraphiQL

Setting up GraphiQL is super easy. All you have to do is add the graphiqlExpress middleware from graphql-server and point it to the GraphQL endpoint we just set up:

server.use('/graphiql', graphiqlExpress({
  endpointURL: '/graphql'
}));

If you now go to http://localhost:4000/graphiql?query={__schema{types{name}}} , you should see the following after pressing the play button and expanding the docs:

This is GraphiQL. It’s pretty amazing.

GraphiQL is going to be an incredibly useful tool to you as a GraphQL developer, so go ahead and play around to familiarize yourself with it. It offers a documentation explorer, syntax highlighting, autocompletion and many more things.

As you’ve probably noticed, running a query like:

{
  channels {
    id
    name
  }
}

Doesn’t actually do anything yet. That’s because we haven’t hooked our GraphQL schema up to any data. So let’s go ahead and do that.

5. Connecting your GraphQL schema to real data

As with the client, the fastest way to get some data into your app is to use mocking. Thanks to GraphQL’s type system, this is incredibly easy. All you have to do is to add this one line to your schema.js file just after the line with makeExecutableSchema and before theexport:

addMockFunctionsToSchema({ schema });

If you run the same query again, you should now get some data with random IDs and “Hello World”. Curious about how it works or how to customize it? You can read about it in one of my posts from last year.

Mocking can be very useful if you want start building your frontend before the backend is done, but since we want to learn how to build a real server, let’s delete the addMockFunctionsToSchema line and write some actual resolve functions!

Let’s go ahead and create another file called resolvers.js in the src folder. In that file we’ll define how the schema should handle a channels query. Rather than connecting to a real persistent backend, which we’ll cover in Part 5 of this tutorial series, we’re just going to define some channels right in our resolvers file:

// src/resolvers.jsconst channels = [{
  id: 1,
  name: 'soccer',
}, {
  id: 2,
  name: 'baseball',
}];export const resolvers = {
  Query: {
    channels: () => {
      return channels;
    },
  },
};

As you probably noticed, resolvers has roughly the same shape as our schema. That’s no accident: Query is the type and channels is one of its fields.

For now, our channels resolve function takes no arguments and simply returns the channels we defined above, but we’ll see some more complex resolve functions that return promises in the next part of this series.

To make our server use the resolve function we just defined, all we have to do is import it in schema.js and pass it to makeExecutableSchema like so:

// schema.js
// ...
import { resolvers } from './resolvers';// ...
const schema = makeExecutableSchema({ typeDefs, resolvers });
export { schema };

Make sure to remove the call to addMockFunctionsToSchema, otherwise your resolve function won’t get applied.

If everything is working, here’s what you should see when you run the query again:

Success!

If something isn’t quite working, you can always browse the solution and compare it against what you ended up with.


Congratulations, you’ve just finished the second part of the tutorial! Here’s what you’ve accomplished: You’ve set up a server, written a GraphQL schema, generated mock data from it, gotten familiar with GraphiQL and even written your first resolver function! You know have the foundation of the server on which we’re going to build a real messaging app throughout the remainder of this tutorial series. In the next part, we’ll connect the server to our existing frontend from Part 1 and write our first mutation:

If you liked this tutorial and want to keep learning about Apollo and GraphQL, make sure to click the “Follow” button below, and follow us on Twitter at @apollographql and @helferjs.

Written by

Jonas Helfer

Jonas Helfer

Read more by Jonas Helfer