In-depth guide on how to get started with GraphQL backend server with Node.js and Apollo

Akshay Gupta
7 min readMay 10, 2018

--

As a passionate developer you are always attracted towards latest trends in the tech industry. Sometimes it gets hard to keep in pace with the ever expanding tech stack, especially in web development.

I came across GraphQL by Facebook recently and got to know about it’s power. It doesn’t take a genius but only a decent development experience to figure out how awesome it can be for your products. Sometimes (not sometimes, most of the times) big companies with existing large scale products tend to miss out on latest technologies because it’s too big an hassle to shift their codebase to latest tech stack, I agree. But, that’s the best part about GraphQL. It is a query language for your API. You don’t need to wreck your existing APIs to integrate GraphQL. It just sits on top of your API and does it’s magic.

There’s a lot to GraphQL. We’ll learn about it’s advantages on the way. For now, let’s get started with an example to make a book library.

(If you are a React Developer , you must watch this talk React State Management In a GraphQL Era by Kristijan Ristovski which inspired me to learn GraphQL)

The full code of this can be found on my github , here .

Initialise the project

Let’s get a few things out of the way

$ mkdir graphql-mongodb-boilerplate
$ cd graphql-mongodb-boilerplate
$ npm init
$ touch server.js

All right, we have initialised the project and made an entry file server.js

Now before we get going let’s install the dependencies we are going to be using in this example.

npm install --save express mongoose body-parser apollo-server-express graphql-tools

Cool, now we are ready , let’s code the shit out of this. Don’t worry if you don’t understand some of dependencies. We’ll cover it as we move forward.

Let’s import some stuff basic stuff in our server.js file and get an express server up and running —

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const app = express();const PORT = 3000;app.listen(PORT, () => {
console.log(
`Server started listening on localhost:${PORT}`
);
});

Because we jump to the GraphQL stuff, let’s setup the database. We are going to use MongoDB for our database. We are going to use mLab for hosting our database. We are also going to use Mongoose, which we have already imported above.

First let’s set up our database hosting. If you are familiar with mLab, go ahead and make a deployment to get the MongoDB URI.

If you’re new and don’t have an account on mLab signup here and once you login you will be redirected to the dashboard. Create a new deployment by clicking on Create New button . Choose any Cloud Provider you worship and create a Sandbox project. Go on and choose Region for your database hosting. Chose the one closest to your location. Chose any Name for your database and Submit Order and BOOM! You’re done.

Just click on the database you created and create a new user for your database. By this time you have a MongoDB URI which looks something like this

 mongodb://<dbuser>:<dbpassword>@ds119160.mlab.com:19160/<dbname>

Now copy this uri and let’s get back to our code.

THE CODE

Let’s make the database config quick and focus on GraphQL

In your root directory, make a folder Config and create a new file databaseconfig.js inside it.

Copy paste this in your databaseconfig.js :

module.exports = {    database: 'mongodb://<dbuser>:<dbpassword>@ds119160.mlab.com:
19160/<dbname>',
secret: '<secret>'}

Import the config file in our entry file server.js and configure mongodb server like so :

// Database Config
const dbconfig = require('./config/databaseconfig');
// connect to mongodb server hosted on mlab
mongoose.connect(dbconfig.database);
var db = mongoose.connection;
db.on('error', (err) => {
console.log(err);});
db.on('open', () => {
console.log("Connected to mongoDB database ...");});

Now we are going to be building a repository for books in this example. Our GraphQL server will be able to query for the books and add the books.

With that in mind let’s make a model for books. Create a new file model.js in project root.

model.js

const mongoose = require('mongoose');const Book = mongoose.model('Book', new mongoose.Schema({
name: String,
author: String;
rating: String;
published: String,
genre: String
}));
module.exports = Book;

This is going to create a model with the above mentioned fields. Do not forget to import the file in server.js

// Model
const Book = require('./model');

Now comes the interesting part, the GraphQL part. GraphQL needs a couple of things to work. It works with the combination of schema and resolvers to fetch us the data we requested in the query. Let’s see how!

In server.js , import this —

const { graphqlExpress, graphiqlExpress }  = require('apollo-server-express');

Wait! What is this apollo-server-express ??!

Apollo Server is a library which helps us to connect our graphQL schema to a server in Node.js. In our case the http server is Express.

Hence, *apollo-server-express*.

graphqlExpress and graphiqlExpress are just middleware who take an object which has a bunch of configuration options we’ll see below.

In server.js add this —

app.use('/graphql',
bodyParser.json(),
graphqlExpress({
schema: executableSchema,
context: { Book }
})
);
app.use('/graphiql',
graphiqlExpress({
endpointURL: '/graphql'
})
);

As I said, middlewares which take config options. In graphqlExpress we provide two configuration options for now schema and context.

context is basically an object which is available for use in every resolver as a third argument. It is an effective way to pass data and use it. Here we are passing Book as context. Remember we mad Book model above and imported it.

schema is just an objet representing our graphQL schema. This is the right time to get started with building our schema.

Make a file schema.js in project root like so —

module.exports = `
type Query {
book(id: String!): Book
books: [Book!]!
}
type Book {
id: String!
name: String
author: String
published: String
genre: String
rating: String
}
type Mutation {
insertBook(
name: String!,
author: String!,
published: String!,
genre: String,
rating: String): Book!
}
`

Remember to wrap your schema in these `` back-ticks.

Every GraphQL service has a Query type. They define entry point of every graphql query . In layman terms, we are telling graphQL service that we are going to query on two things here.

— First, book(id: String!) : Book, that means we can query a book by providing it’s id. The ‘!’ exclamation mark says that it’s compulsory we provide ‘id’ for this query to run and this query is going to return an object of type Book which is described above by type Book {} .

— Second, books: [Book!]! to tell that we can query for all the books which is going to return an array of Books.

Apart from Query type, GraphQL service can also have Mutation type. We might want to modify data on server side as well. This modification process , GraphQL calls it Mutation. Mutation types simply describes a function which takes some arguments and returns the mutation result, in our case a Book object. The ‘!’ means the same thing here, it’s important that we provide name and author while we make the query.

Import the schema in server.js like so -

// Schema
const Schema = require('./schema');

Now, just describing a schema is not going to do the magic. Schema is just a structure. We need a way to implement this structure . This implementation is going to describe the server’s behaviour. The component which does this implementation are called resolvers.

Make a file resolver.js in root like so —

module.exports = {
Query: {
books: async (parent, args, { Book }) => {
const books = await Book.find({});
return books.map((book) => {
book._id = book._id.toString();
return book;
});
}
book: async (parent, args, {Book}) => {
const book = await Book.findById(args.id);
if(book) return book;
else throw new Error('No book with this ID found');
}
},
Mutation: {
insertBook: async (parent, args, { Book }) => {
const book = await Book(args).save();
book._id = book._id.toString();
return book;
}
}
}

This simple resolver object has a query resolver and mutation resolver. We can resolve query by book and books like we mentioned in schema described above. Each resolver takes a parent, args, and context.

args : It contains the arguments we are going to pass the query. For example: to get books by id, we are going to pass id which is going to be accessible by args.id.

context: Remember we passed the context in our entry file.

We also defined the Mutation we made earlier ‘insertBook’. The args in our . mutation contains the object we are going to pass which contains the data for the book.

Now that we have our resolver ready import it in our server.js file.

// Resolver
const Resolver = require('./resolver');

Now, copy-paste this code in server.js file too :

const Schema = makeExecutableSchema({
typeDefs: Schema,
resolvers: Resolver
});

The graphql-tools package allows you to create a GraphQL.js GraphQLSchema instance from GraphQL schema language using the function makeExecutableSchema

For this we need to import makeExecutableSchema first

const { makeExecutableSchema } = require('graphql-tools');

What happened here is that we combined Schema and Resolvers using makeExecutableSchema.

Alright, we are almost done. One last thing left. Our server is now going to listen to localhost:3000/graphiql which we can go to to open GraphiQL interface to query data and check if our server is working as expected.

So change your app.listen() method to :

app.listen(PORT, () => {
console.log(
`Server started listening on localhost:${PORT}/graphiql`
);
});

Or don’t. Doesn’t matter!

Run npm start and go to localhost:3000/graphiql , which opens a window like this :

Congratulations, you have just made a simple graphQL server. Before we close let’s take a look at sample queries.

Mutation :

mutation newBook {
insertBook(
name: "The Great Gatsby",
author: "F. Scott Fitzgerald",
published: "1925",
rating: "3.9/5",
genre: "Historical Fiction"
){
id
name
author
}
}

Query Data :

query getAllBooks {
books {
id
name
author
published
genre
rating
}
}
query getBookById($id: String!) {
book(id: $id) {
id
name
author
}
}

That’s all from my side.

This was my first article! Any suggestions would be much appreciated and welcomed. Don’t forget to give clap if you liked it.

Thank you :)

--

--