Build a Simple Blog API with Express, ES6+ and MongoDB


Build a Simple Blog API with Express, ES6+ and MongoDB

Recipe ID: hsts-r1


Blog Api with Express, ES6+ and MongoDB (intermediate level)

Download source files for this recipe

Overview

Express is an awesome framework for creating fast web APIs to interface with your SPA and because it’s also in JavaScript, your entire codebase can be developed in 1 language. The makes it easier to use all of the same familiar tools if you’re integrating with React JS or Angular.
In this recipe, we’ll create a simple blog API that returns a list of blog posts to the user. In later posts, we’ll cover JWT authentication and user relationships with MongoDB but for now, we’ll focus on basic CRUD.

Pre Requisites

  • Good Knowledge of JavaScript, Express and MongoDB

Learning Objectives

  • After the end of this recipe you will be familiar with express.js
  • You will have a great hand over MongoDB
  • Will have a command over JavaScript in more Depth

Project Setup with NPM

In order to create our application, we’re first going to have to setup out npm configuration and make sure that we specify that our project uses the ES6 syntax.
Create a project folder in the command line by running

mkdir ExpressAPIBlog && cd ExpressAPIBlog 
Copy

Now that you are in the directory, create a package.json and add you dev dependencies

npm init
npm install --save-dev babel-cli babel-preset-stage-0 babel-preset-env 
Copy

This will allow for you to compile your ES6 code to ES5 so that it is understood by Express.JS and Node.
Now in order to actually build your application, you have to add each of these dependencies with npm.

npm install body-parser cuid express limax mongoose sanatize-html 
Copy

Now that everything is installed, create a file called server.js

import express from 'express'; 
import bodyParser from 'body-parser'; 
let app = express(); 
app.use(bodyParser.json()); 
app.use(bodyParser.urlencoded({ 
    extended: false 
})); 
app.get('/', (req, res) => res.send('Hello World!')); 
 
app.listen(3005, () => { 
    console.log('server started - 3005'); 
}); 
Copy

Then add a script to your package.json file to run the server

"scripts": { 
    "start": "babel-node server.js --presets env", 
    "test": "echo \"Error: no test specified\" && exit 1" 
  }, 
Copy

Database Setup with Mongoose

Now that express is working, let’s set up a database connection.
First off, let’s create a config file that specifies our connection to the database instance

mkdir config && touch config/index.js 
Copy

Open the file and add the port number and database connection string.

export default { 
    "port": 3005, 
    "mongoUrl": "mongodb://localhost:27017/express-api-blog", 
    "bodyLimit": "100kb" 
} 
Copy

Once that is done, create a database file that connections your express app to Mongo DB.

mkdir db && touch db/connect.js 
Copy
import mongoose from 'mongoose'; 
import config from '../config/index'; 
 
mongoose.Promise = global.Promise; 
 
const connectToDb = async () => { 
    try { 
        await mongoose.connect(config.mongoUrl, { useMongoClient: true }); 
        
    } 
    catch (err) { 
        
      console.log(err); 
    } 
} 
 
export default connectToDb; 
Copy

Here you create an asynchronous function that tries to connect to the DB and if it fails, it consoles out the error.

Creating the Model

Next we have to create the Model for the post. This represents each post that goes into the database.

mkdir models && touch post.js 
Copy

Inside of this model we will add a title along with the post content, a date the post was created at, a slug that will be generated based on the title and a cuid which is an id number. Even though all Mongoose documents have a _id field by default, cuid is another great way to have collision resistant ids

import mongoose from 'mongoose'; 
const Schema = mongoose.Schema; 
 
const postSchema = new Schema({ 
    title: { type: 'String', required: true }, 
    content: { type: 'String', required: true }, 
    slug: { type: 'String', required: true }, 
    cuid: { type: 'String', required: true }, 
    dateAdded: { type: 'Date', default: Date.now, required: true }, 
}); 
 
let Post = mongoose.model('Post', postSchema); 
 
export default Post; 
Copy

Express Controller Actions

Now that we have our database setup and the model that we would like to use to populate the database, now we must figure out a way to allow the user to send requests to the API to create new posts. We could place all of the requests inside of the server.js file but it’s much cleaner to create a controller file.

mkdir controllers && touch controllers/post.controller.js 
Copy

Inside of this controller we are going to need 5 CRUD functions. A get all, get by Id, create, update and delete.

import Post from '../models/post'; 
import cuid from 'cuid'; 
import slug from 'limax'; 
import sanitizeHtml from 'sanitize-html'; 
 
const PostController = {}; 
Copy

We’ve created a controller object to make it easy to export all of the functions that we’ll be creating.
The first function will actually be the getAll() function.

PostController.getAll = async (req, res) => { 
    try{ 
        await Post.find().sort('-dateAdded').exec((err, posts) => { 
            if (err) { 
                res.status(500).send(err); 
            } 
            res.json({ posts }); 
        }); 
    } 
    catch(err){ 
        res.send(err); 
    } 
} 
Copy

This function takes in the request, tries the function and returns a a list of posts or an err depending on where the error takes place.
Then we have the getPost function. This finds the post by it’s cuid and returns the post if it exists.

PostController.getPost = async (req, res) => { 
    try{ 
        Post.findOne({ cuid: req.params.cuid }).exec((err, post) => { 
            if (err) { 
                res.status(500).send(err); 
            } 
            res.json({ post }); 
        }); 
    } 
    catch(err){ 
 
    } 
} 
Copy

Next, we have the addPost function. This checks if either the title or content is not present, creates the post, sanitizes the content, then saves the Post to the database.

PostController.addPost = async (req, res) => { 
    try { 
        if (!req.body.post.title || !req.body.post.content) { 
            res.status(403).end(); 
        } 
 
        const newPost = new Post(req.body.post); 
 
        // Sanitize inputs 
        newPost.title = sanitizeHtml(newPost.title); 
        newPost.content = sanitizeHtml(newPost.body); 
 
        newPost.slug = slug(newPost.title.toLowerCase(), { lowercase: true }); 
        newPost.cuid = cuid(); 
 
        newPost.save((err, saved) => { 
            if (err) { 
                res.status(500).send(err); 
            } 
            res.json({ post: saved }); 
        }); 
    } 
    catch (err) { 
        console.log(err); 
    } 
} 
Copy

UpdatePost is very similar to addPost except it finds the post by it’s cuid, then updates the fields.

PostController.updatePost = async (req, res) => { 
    try { 
        if (!req.body.post.title || !req.body.post.content) { 
            res.status(403).end(); 
        } 
        Post.findOne({ cuid: req.params.cuid }).exec((err, post) => { 
            // Handle database errors 
            if (err) { 
                res.status(500).send(err); 
            } else { 
                post.title = req.body.post.title || post.title; 
                post.content = req.body.post.content || post.content; 
                console.log('Post about to be saved'); 
                // Save  
                post.save((err, saved) => { 
                    if (err) { 
                        res.status(500).send(err) 
                    } 
                    res.json({ post: saved }); 
                }); 
            } 
        }); 
    } 
    catch (err) { 
        console.log(err); 
    } 
} 
Copy

For the DELETE Request, we have deletePost. This takes the cuid and deletes the post with that id. At the end, we also export the controller.

PostController.deletePost = async (req, res) => { 
    try { 
        Post.findOne({ cuid: req.params.cuid }).exec((err, post) => { 
            if (err) { 
                res.status(500).send(err); 
            } 
 
            post.remove(() => { 
                res.status(200).end(); 
            }); 
        }); 
    } 
    catch (err) { 
        console.log(err); 
    } 
} 
 
export default PostController; 
Copy

Express Routing

Even though we now have our controller set up, we’ll need a way to access the routes in our controller. This can easily be done by creating a routing file. In your command line run

mkdir routes && touch routes/posts.routes.js 
Copy

Inside of your server.js file, add

import posts from './routes/posts.routes'; 
 
 
app.use('/api', posts); 
Copy

Now open your posts.routes file and import the express router and your controller.

import { Router } from 'express'; 
import PostController from '../controllers/post.controller'; 
const router = new Router(); 
Copy

This will allow for you to map get, post, put and delete requests to your controller methods.

// Get all Posts 
router.get('/posts', (req, res) => { 
    PostController.getAll(req, res); 
}); 
 
// Get one post by cuid 
router.get('/posts/:cuid', (req, res) =>{ 
    PostController.getPost(req,res); 
}); 
 
// Add a new Post 
router.post('/posts', (req, res) => { 
    PostController.addPost(req, res); 
}); 
 
router.put('/posts/:cuid', (req, res) => { 
    PostController.updatePost(req, res); 
}); 
 
// Delete a post by cuid 
router.delete('/posts/:cuid', (req, res) => { 
    PostController.deletePost(req, res); 
}); 
export default router; 
Copy

Once this is done, we should be ready to test our API.

Testing API Routes with Insomnia

Lets start off by creating a few posts. Run the server with

npm run-script start 
Copy

and create a few posts with
Express Blog API Create
Express Blog API Create
Do this several time and then do a get request to return all posts
Get Request Express Blog API
Get Request Express Blog API
You can also use a tool like Compass to view all of your MongoDB Documents
MongoCompass Expres Blog API
MongoCompass Expres Blog API
Now let’s try testing out getting a post by it’s id.
GetByCUID Express Blog API
GetByCUID Express Blog API
Also by passing in the cuid and the modified contents, we can update the post.
Put Request Blog API Express
Put Request Blog API Express
Finally we have the DELETE Request. This can be done just by passing in the cuid.
Delete-Request-Express-Blog-API
Delete-Request-Express-Blog-API

Conclusion

Here the API has been built up, currently setting up a REST API with ES6 currently requires a lot of tooling to compile the JavaScript but it offers the ability to write cleaning, more maintainable code.

Related Training Courses

JavaScript and jQuery Introduction
PHP and MySQL Coding
Advance Website Design Using HTML and CSS
Cross-platform Native App Development Using HTML5, CSS3 and JavaScript
jQuery Programming for Beginners
Intro to Dreamweaver with Website Development Training
Adobe Muse Training Course
Introduction to the WordPress CMS
Introduction to the Joomla CMS
Mastering Drupal in 30 Hours
SQL Programming and Database Management


Private and Custom Tutoring

We provide private tutoring classes online and offline (at our DC site or your preferred location) with custom curriculum for almost all of our classes for $50 per hour online or $75 per hour in DC. Give us a call or submit our private tutoring registration form to discuss your needs.


View Other Classes!