06 Feb 2019

Start with a GraphQL API, Apollo, Sequelize, PostgreSQL, Node.js and Express.js

Easy to read, short tutorial, on how to setup a GraphQL API with Apollo, Sequelize, PostgreSQL, Node.js and Express.js.

Introduction

I was reading about GraphQL multiple times in the past, but never did get time to actually try it out. This time I decided to change that, so after reading a few tutorials online, I decided to setup my own GraphQL project and write short notes on how to do that easily.

Grab the tool

If you did not hear about easyship CLI before, that’s my own tool to easily get projects up and running. To setup this project grab the easyship CLI and set it up as described in instructions. For purposes of this tutorial we will use nodeship.

Project creation

Before we can start with GraphQL setup we have to create a new project. First create node project by running nodeship create empty node-graphql-tutorial.

Once project is created we can enter project directory (cd node-graphql-tutorial) and proceed with installing dependencies. To install all the dependencies, run the command:

npm i apollo-server-express body-parser express graphql pg pg-hstore sequelize --save

We also have to install some dev dependencies that will be used to generate database data:

npm i faker lodash.random lodash.times --save-dev

Once we have have all the dependencies we can start with writing some code.

Database setup

Head to the project root and create file named db-config.json. This file will contain database connection info:

{
  "development": {
    "username": "postgres",
    "password": "postgres",
    "database": "node-graphql-tutorial",
    "host": "127.0.0.1",
    "dialect": "postgres"
  }
}

We also need some code to establish db connection and to map our models into database. For this purpose we will use PostgreSQL and Sequilize. Add this code into src/db.js:

import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';

const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require('../db-config.json')[env];
const db = {};

const sequelize = new Sequelize(config.database, config.username, config.password, config);

fs.readdirSync(path.join(__dirname, '/models'))
    .filter(file => file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js')
    .forEach(file => {
        const model = sequelize.import(path.join(__dirname, '/models', file));
        db[model.name] = model;
    });

Object.keys(db).forEach(modelName => {
    if (db[modelName].associate) {
        db[modelName].associate(db);
    }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

export default db;

This code will establish db connection and sync all models from src/models directory into database. So, let’s create some models. Create src/models/post.js file with content:

export default (sequelize, DataTypes) => {
    const Post = sequelize.define('post', {
            id: {
                type: DataTypes.INTEGER,
                primaryKey: true,
                autoIncrement: true
            },
            title: DataTypes.STRING,
            content: {
                type: DataTypes.TEXT,
                allowNull: false
            }
        },
        {
            freezeTableName: true
        }
    );

    Post.associate = (models) => {
        Post.belongsTo(models.author);
    };

    return Post;
}

And also src/models/author.js with a content:

export default (sequelize, DataTypes) => {
    const Author = sequelize.define('author', {
            id: {
                type: DataTypes.INTEGER,
                primaryKey: true,
                autoIncrement: true
            },
            firstName: DataTypes.STRING,
            lastName: DataTypes.STRING
        },
        {
            freezeTableName: true
        }
    );

    Author.associate = (models) => {
        Author.hasMany(models.post);
    };

    return Author;
};

With this we should have our database connection and ORM ready.

GraphQL setup

Now it is time to create GraphQL schema and resolvers. Create a new directory on path src/graphql. Into directory first add file src/graphql/schema.js with a content:

export default `
  type Author {
    id: ID!
    firstName: String!
    lastName: String!
    posts: [Post!]!
  }
  type Post {
    id: ID!
    title: String
    content: String!
    authorId: ID!
    author: Author!
  }
  type Query {
    posts: [Post!]!
    post(id: ID!): Post
    author(id: ID!): Author
    authors: [Author!]!
  }
  type Mutation {
    createPost(title: String, content:String!, authorId: ID!): Post!
    updatePost(id: ID!, title: String, content:String!): [Int!]!
    deletePost(id: ID!): Int!
  }
`;

When done, create another file on path src/graphql/resolvers.js:

export default {
    Author: {
        posts: (parent, args, context, info) => parent.getPosts(),
    },
    Post: {
        author: (parent, args, context, info) => parent.getAuthor(),
    },
    Query: {
        posts: (parent, args, { db }, info) => db.post.findAll(),
        authors: (parent, args, { db }, info) => db.author.findAll(),
        post: (parent, { id }, { db }, info) => db.post.findById(id),
        author: (parent, { id }, { db }, info) => db.author.findById(id)
    },
    Mutation: {
        createPost: (parent, { title, content, authorId }, { db }, info) =>
            db.post.create({
                title: title,
                content: content,
                authorId: authorId
            }),
        updatePost: (parent, { title, content, id }, { db }, info) =>
            db.post.update({
                    title: title,
                    content: content
                },
                {
                    where: {
                        id: id
                    }
                }),
        deletePost: (parent, {id}, { db }, info) =>
            db.post.destroy({
                where: {
                    id: id
                }
            })
    }
};

With this code, all we need for our GraphQL is ready. Now it is time to start our node.js server.

Server

Inside src/index.js add this code:

import express from 'express';
import {
    ApolloServer,
    gql
} from 'apollo-server-express';
import typeDefs from './graphql/schema';
import resolvers from './graphql/resolvers';
import db from './db';

import faker from 'faker';
import times from 'lodash.times';
import random from 'lodash.random';

const server = new ApolloServer({
    typeDefs: gql(typeDefs),
    resolvers,
    context: { db }
});

const app = express();
server.applyMiddleware({ app });

db.sequelize.sync().then(() => {
    // populate author table with dummy data
    db.author.bulkCreate(
        times(10, () => ({
            firstName: faker.name.firstName(),
            lastName: faker.name.lastName()
        }))
    );

    // populate post table with dummy data
    db.post.bulkCreate(
        times(10, () => ({
            title: faker.lorem.sentence(),
            content: faker.lorem.paragraph(),
            authorId: random(1, 10)
        }))
    );

    app.listen({ port: 4000 }, () =>
        console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
    );
});

Before starting our server, make sure you created database named node-graphql-tutorial on your PosgreSQL server and user is configured correctly (check db-config.json file and modify it to suit your needs).

When ready just run nodeship dev from project root.

Playground

If everything passed well, you should be able to navigate to a playground with your browser. When open, you should see a page like this:

On playground you can write GraphQL queries and even export them to curl and run through console. To learn more about GraphQL, head to GraphQL official page.

Whole source code written for this tutorial can be found on this link.

Happy coding!