Creating an API with GraphQL, MongoDB, and Express
📣 Sponsor
GraphQL is a language built primarily for use with APIs. It interacts with Javascript and other languages quite easily. In this article, let's take a look at the basics around how to combine Express, MongoDB, and GraphQL into a basic API for getting titles and dates from a database.
GraphQL is a bit of a departure from classic REST APIs, but once you get used to it you'll see how easy it can be to run. Let's take a look.
Install GraphQL
The first step is to install the standard graphql packages and expresss on your Node.JS server by running the below installs on the command line:
npm i graphql
npm i graphql-express
npm i express
npm i mongoose
A basic GraphQL Express Endpoint
Let's start with a functional express/GraphQL server. Create a file called index.js
and insert this code:
import express from 'express';
import { graphqlHTTP } from 'express-graphql';
import { buildSchema } from 'graphql'
/* A schema is used to define how the data will look */
let schema = buildSchema(`
type Query {
title: String,
age: Int,
description: String
}
`);
/* A root value is used to say what will be RETURNED for each schema element */
let root = {
title: () => { return "Fjolt" },
age: () => { return 5 },
description: () => { return 'A website' }
};
/* We tie it all together with express, so a user can access the endpoint */
let app = express();
app.get('/api', graphqlHTTP({
schema: schema,
rootValue: root
}));
app.listen(4000);
As you can see, there are three main pieces required for GraphQL. First, we define a schema, which is the type of data our endpoint will return. Every GraphQL requires a 'type Query
' schema, but after that you can use any name you want instead of 'Query'. You could have a type TeamMember
schema, for example.
Next we have our root values. These are the items from the schema, and related functions which return a value for each. If a user then tries to get 'age
' from the API, they will get a return of 5.
Finally, we return the data when the user does a GET
request from /api. If you have Postman installed (which I would recommend for this tutorial), you can easily send a query with GraphQL like this to see how it works.
GraphQL has a very simple query language where we only need to send the keys of the elements we want in curly brackets. You can even do this at multiple levels for a multi-level object. An example is shown below:
Schemas
GraphQL has a specific query language which allows us to create schemas. Schemas are essentially definitions for the type of data our API will return. A user could then send a query, to select specific components of that Schema.
Root Values
Root values are objects of all things in the schema.
Variables
It is also possible to add variables into the mix. To do that, we just need to define the variables in both the schema and the rootValue. We have to wrap our our variables in the rootValue in {}
brackets.
let schema = buildSchema(`
type Query {
title(firstName: String, lastName: String): String
// ...
}
`);
let root = {
title: ({firstName, lastName}) => { return firstName + ' ' + lastName }
// ...
};
We can then query the title variable in Postman with the following query:
Combining with MongoDB
Now we have a simple GraphQL interface, lets combine it with MongoDB. Create a file with your mongoDB schema. Mine is about articles, so it looks a little like what we've got below. Note, the schema here for the database is different, but that won't stop us:
import mongoose from 'mongoose'
const database = 'mongodb://localhost:27017/articles';
const connection = mongoose.createConnection(database, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const schema = new mongoose.Schema({
title: 'String',
description: 'String',
articleText: 'String',
date: 'Number'
});
const Article = connection.model('Article', schema);
export { Article };
Combine MongoDB
So first of all, add your new model to your index.js file, where you had your express router from before. Don't forget to connect to your mongoDB if you need to as well:
// Import mongoose
import mongoose from 'mongoose';
// Models
import { Article } from './models/article.model.js';
// Connect to our mongoDB
const database = 'mongodb://localhost:27017/database';
mongoose.connect(database, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
Update our root and model
For this, I want to return all titles from my database and all page dates in separate arrays. First of all, let's update our schema to reflect that graphQL should return arrays of items:
let schema = buildSchema(`
type Query {
title: [String]
articleAge: [Int]
}
`);
Easy. Next, let's update our root variable. This time, we will connect to our mongoDB to return the articles, and compress them into one dimensional arrays:
let root = {
title: async () => {
let allArticles = [];
// Query our mongoDB
let articles = await Article.find();
// Return data in appropriate format
articles.forEach(function(item) {
if(typeof item.title === "string") {
allArticles.push(item.title);
}
});
return allArticles;
},
articleAge: async () => {
// Repeat
let allDates = [];
let articles = await Article.find();
articles.forEach(function(item) {
if(typeof item.date === "number") {
allDates.push(item.date);
}
});
return allDates;
}
};
Now we can run our API with the same query style as before, to get all our article dates and titles:
Conclusion
That's all for today. If you're interested in learning more with us, follow us on twitter via @thisisfjolt to get the latest articles.
Here are some useful resources, and the code from today's final example.