Server-side implementation

Server-side code is located here https://github.com/KilroggD/GraphQL-react/tree/master/graphsrv

Before we start creating our server-side application we need several npm packages installed — you can find package.json in the repository:

"dependencies": {

"express": "^4.16.2",

"express-graphql": "^0.6.11",

"graphql": "^0.11.7",

"lodash": "^4.17.4",

"babel-cli": "^6.24.1",

"babel-preset-node6": "^11.0.0",

"babel-register": "^6.24.1",

"nodemon": "^1.11.0"

}

Here we can see express framework, graphql extension, the lodash library — extremely useful for filtering and searching in JS arrays — and some additional package to run our server and make it understand fancy ES6 syntax.

Our entry point is our server.js file. First we import all necessary modules and define a port our server listens to, then create our express app. We also import the GraphQL schema file that will be described later.

import express from 'express';

import schema from './schema';

import graphqlHTTP from 'express-graphql';

const port = 3001;

const app = express();

After that we need to describe what our app is going to do. At first we assume that our API might be public, or that our front-end dev server could be run on a different port, so we need to allow cross-origin requests.

app.use('/graphql', (req, res, next) => {

res.header('Access-Control-Allow-Origin', '*');

res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

if (req.method === 'OPTIONS') {

res.sendStatus(200);

} else {

next();

}

});

Then we write four magic lines of code which do the GraphQL work:

app.use('/graphql', graphqlHTTP({

schema,

graphiql: true

}));

Graphiql is a powerful development tool which allows you to dev-test your API without having any frontend or client applications. In other words, this bit of code is the only endpoint we need. It will process all POST requests sent to http://localhost:3001/graphql via our GraphQL schema.

And, finally, the code that launches the server itself:



console.log(

`



Express listen at

);

}); const server = app.listen(port, () => {console.log(`



Express listen at http://localhost:${port }

`);});

Now let’s define the main part of our server-side application — the Schema. It defines all rules about how our requests will be validated, how the results will be taken from the data source, which relations different entities have between each other, etc. So it basically works like a data model for our application.

First, we will import our data source files and useful lodash methods for filtering and aggregating data. Do not import the whole lodash library just for the couple of function you’re going to use (NO import _ from lodash!)

import Users from './data/users';

import Todos from './data/todos';

import find from 'lodash/find';

import filter from 'lodash/filter';

import sumBy from 'lodash/sumBy';

After that we import some GraphQL classes for type validation and creating Schema objects

import {

GraphQLInt,

GraphQLBoolean,

GraphQLString,

GraphQLList,

GraphQLObjectType,

GraphQLNonNull,

GraphQLSchema,

} from 'graphql';

Then we can define the actual data structures for entities we need. In this example we have two entities — one for users and one for todos:

const UserType = new GraphQLObjectType({

name: 'User',

description: 'Users in company',

fields: () => ({

id: {type: new GraphQLNonNull(GraphQLInt)},

first_name: {type: new GraphQLNonNull(GraphQLString)},

last_name: {type: new GraphQLNonNull(GraphQLString)},

email: {type: GraphQLString},

gender: {type: GraphQLString},

department: {type: new GraphQLNonNull(GraphQLString)},

country: {type: new GraphQLNonNull(GraphQLString)},

todo_count: {

type: GraphQLInt,

resolve: (user) => {

return sumBy(

Todos, todo => todo.userId === user.id ? 1:0

);

}

},

todos: {

type: new GraphQLList(TodoType),

resolve: (user, args) => {

return filter(

Todos, todo => todo.userId === user.id

);

}

}

})

});

Here, for all fields except todo_count and todos we have only types defined (Int, String etc.). For those two types related to another entity (todos) we define a resolve function which will, in the first case aggregate the number of todos, and in the second case just fetch all todos related to the user. Then we define similar functions for todos with relation to the user the task is assigned to.

const TodoType = new GraphQLObjectType({

name: 'Todo',

description: 'Task for user',

fields: () => ({

id: {type: new GraphQLNonNull(GraphQLInt)},

title: {type: GraphQLString},

completed: {type: new GraphQLNonNull(GraphQLBoolean)},

user: {

type: UserType,

resolve: (todo, args) => {

return find(Users, user => user.id === todo.userId);

}

}

})

});

After all data types are defined we can create a root query for our application. There are different types of queries in GraphQL, but for this example we will just focus on a very simple one which fetches data from data source. For users we will also implement filtering parameters, and for todos we will just fetch all items related to the userId given. Here’s the code for our main query:

const TodoQueryRootType = new GraphQLObjectType({

name: 'TodoAppSchema',

description: 'Root Todo App Schema',

fields: () => ({

users: {

args: {

first_name: {type: GraphQLString},

last_name: {type: GraphQLString},

department: {type: GraphQLString},

country: {type: GraphQLString},

},

type: new GraphQLList(UserType),

description: 'List of Users',

resolve: (parent, args) => {

if (Object.keys(args).length) {

return filter(Users, args);

}

return Users;

}

},

todos: {

args: {

userId: {type: GraphQLInt},

completed: {type: GraphQLBoolean},

},

type: new GraphQLList(TodoType),

description: 'List of Todos',

resolve: (parent, args) => {

if (Object.keys(args).length) {

return filter(Todos, args);

}

return Todos;

}

}

})

});

Here our main application Schema is described. It has two fields — users and todos with UserType and TodoType respectively. We can filter Users list by four possible parameters defined in args. The filter itself is implemented in a resolve function (in this case just a simple lodash filter).

The same goes for the Todos list: we can potentially filter it by userId and by completed state.

Finally, we create and export our schema object:

const schema = new GraphQLSchema({

query: TodoQueryRootType,

}); export default schema;

At this point you can already launch your sever and test it via the debug tool.

Just open http://localhost:3001/graphql in your Chrome browser and try some queries mentioned earlier in this story.

At this point the server-side is finished and we can start with the client side part.