How to run your own GraphQL server

In our ongoing exploration of GraphQL, it is time to start your own server. This post will describe how to do embed a GraphQL server inside a node application.

Now that we know a little bit more about GraphQL schemas, it may be time to write our own schema and to run your own GraphQL server using express.

Facebook helper libraries

Facebook provide 3 libraries to help you build your own GraphQL server.

graphql-js

This is a Javascript reference implementation for GraphQL. This library provides the API you need to build your own GraphQL schema.

In the __tests__ directory there is a test schema that we can use to test our GraphQL server.

express-graphql

This library provides an express middleware to handle GraphQL requests.

GraphiQL

In order to test your schema, GraphiQL provides a set of react components that you can assemble in a static web page to test your schema.

Steps to run your own GraphQL server

You need to node install the following modules :

What about graphiql ?

For GraphiQL, you want to get a static html file and the associated .css and .js files to compose the GraphiQL web interface.

I found it easier to build those directly from the git repo:

(you need to have browserify and uglifyjs globaly installed for the following scripts to work)

$ git clone git@github.com:graphql/graphiql.git
$ cd graphiql
$ npm install
# this is the script which actually builds graphiql.min.js, graphiql.js and graphiql.css
$ . ./resources/build.sh

You then create a directory named static where you copy the files you need for the web interface:

$ mkdir ../static
$ cp graphiql.css graphiql.min.js graphiql.js example/index.html ../static

You can then delete the graphiql directory. All we need is in the static directory.

Star wars GraphQL schema

In order to test your server, you will need a GraphQL server. You can use the Star Wars schema provided with graphql-js in the __tests__ directory and copy those 2 files in your directory:

You will have to slightly change the starWarsSchema.js to replace the name of imported module because we are using here the graphql module:

import {
  GraphQLEnumType,
  GraphQLInterfaceType,
  GraphQLObjectType,
  GraphQLList,
  GraphQLNonNull,
  GraphQLSchema,
  GraphQLString,
} from '../type';

to:

.../...
  GraphQLString,
} from 'graphql';

GraphQL server.

The GraphQL server per se is a simple express application:

import express from 'express';
import graphqlHTTP from 'express-graphql';

var path = require('path');

export default function(schema, port) {
  var app = express();
  app.use(express.static(path.join(__dirname, 'static')));
  app.use('/graphql', graphqlHTTP(function() {
    return {
      schema: schema
    };
  }));

  app.use('/schema', function(req, res, _next) {
    var printSchema = require('graphql/utilities/schemaPrinter').printSchema;
    res.set('Content-Type', 'text/plain');
    res.send(printSchema(schema));
  });

  app.listen(port);
  console.log(`Started on http://localhost:${port}/`);
}

A few things to highlight :

Main program

Finally, you need a simple main.js to glue everything together:

import graphqlServer from './server';
import { StarWarsSchema } from './starWarsSchema.js';

graphqlServer(StarWarsSchema,8080);

Testing your GraphQL server

At this stage, you should have this directory structure:

.
├── main.js
├── node_modules
│   ├── express
│   ├── express-graphql
│   ├── graphql
│   └── react
├── server.js
├── starWarsData.js
├── starWarsSchema.js
└── static
    ├── graphiql.css
    ├── graphiql.js
    ├── graphiql.min.js
    └── index.html

As the javascript code is written in es6, you must run it using babel-node (or convert it to es5):

$  babel-node main.js
Started on http://localhost:8080/

You then point your browser to http://127.0.0.1:8080/ and enter your first query.

(you should read the code of starWarsData.js to get the ids of the different entities of the model)

GraphQL query GraphQL response
{
  human(id: "1000") {
    name
    friends {
      name
    }
  }
}
{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "friends": [
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        },
        {
          "name": "C-3PO"
        },
        {
          "name": "R2-D2"
        }
      ]
    }
  }
}

and if you go to http://127.0.0.1:8080/schema you get the schema

interface Character {
  id: String!
  name: String
  friends: [Character]
  appearsIn: [Episode]
}

type Droid implements Character {
  id: String!
  name: String
  friends: [Character]
  appearsIn: [Episode]
  primaryFunction: String
}

enum Episode {
  NEWHOPE
  EMPIRE
  JEDI
}

type Human implements Character {
  id: String!
  name: String
  friends: [Character]
  appearsIn: [Episode]
  homePlanet: String
}

type Query {
  hero(episode: Episode): Character
  human(id: String!): Human
  droid(id: String!): Droid
}

:relieved:

Voilà!