Creating RESTful APIs with Express 4

By Sandeep Panda

With the release of Express 4 it has gotten even easier to create RESTful APIs. If you are creating a Single Page App you will definitely need a RESTful web service which supports CRUD operations. My last tutorial focussed on creating a Single Page CRUD app with Angular’s $resource. This tutorial explains how to design the backend API for such a CRUD app using Express 4.

Just note that a lot has been changed since Express 3. This tutorial doesn’t explain how to upgrade your app from Express 3 to Express 4. Rather it will cover how to create the API with Express 4 directly. So, let’s get started.

Creating the API for the Movie App

Our app will be a simple movie database which supports basic CRUD operations. We will use Express 4 as the web framework and MongooseJS as the object modeling tool. To store the movie entries we will use MongoDB.

Before going further let’s take a look at what the API will look like:

API Overview

Directory Structure

We will use the following directory structure in our app:

App Directory Structure

Here are some points about the above directory structure:

  1. The bin/www.js is used to bootstrap our app.
  2. The models directory stores our mongoose models. For this app we will have just one file called movie.js.
  3. The routes directory will store all the Express routes.
  4. The app.js holds the configurations for our Express app.

Finally, node_modules and package.json are the usual components of a Node.js app.

Obtaining Necessary Dependencies

To create the API we will use the following modules:

  1. Express
  2. Body parser
  3. Mongoose

Notebody-parser is not a part of the Express core anymore. You need to download the module separately. So, we have listed it in the package.json.

To obtain these packages we will list them as dependencies in our package.json. Here is our package.json file:

  "name": "Movie CRUD API",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  "engines": {
     "node": "0.10.x"
  "dependencies": {
    "express": "~4.2.0",
    "body-parser": "~1.0.0",
    "mongoose": "~3.8.11"

Just run npm install and all the dependencies will be downloaded and placed under the node_modules directory.

Creating the Model

Since we are building an API for a movie database we will create a Movie model. Create a file named movie.js and put it in the models directory. The contents of this file, shown below, create a Mongoose model.

var mongoose=require('mongoose');
var Schema=mongoose.Schema;

var movieSchema = new Schema({
  title: String,
  releaseYear: String,
  director: String,
  genre: String

module.exports = mongoose.model('Movie', movieSchema);

In the previous snippet we create a new model, Movie. Each movie has four properties associated with it – title, release year, director, and genre. Finally, we put the model in the module.exports so that we can access it from the outside.

Creating the Routes

All of our routes go in routes/movies.js. To start, add the following to your movies.js file:

var Movie = require('../models/movie');
var express = require('express');
var router = express.Router();

Express 4 has a new method called express.Router() which gives us a new router instance. It can be used to define middlewares and routes. The interesting point about Express router is that it’s just like a mini application. You can define middlewares and routes using this router and then just use it in your main app just like any other middleware by calling app.use().

Getting All the Movies

When users send a GET request to /api/movies, we should send them a response containing all the movies. Here is the snippet that creates a route for this.

router.route('/movies').get(function(req, res) {
  Movie.find(function(err, movies) {
    if (err) {
      return res.send(err);


router.route() returns a single route instance which can be used to configure one or more HTTP verbs. Here, we want to support a GET request. So, we call get() and pass a callback which will be called when a request arrives. Inside the callback we retrieve all the movies using Mongoose and send them back to the client as JSON.

Creating a New Movie

Our API should create a new movie in the database when a POST request is made to /api/movies. A JSON string must be sent as the request body. We will use the same route, /movies, but use the method post() instead of get().

Here is the code:

router.route('/movies').post(function(req, res) {
  var movie = new Movie(req.body); {
    if (err) {
      return res.send(err);

    res.send({ message: 'Movie Added' });

Here, we create a new Movie instance from the request body. This is where body-parser is used. Then we just save the new movie and send a response indicating that the operation is successful.

Note that the methods get(), post(), etc. return the same route instance. So, you can in fact chain the previous two calls as shown below.

  .get(function(req, res) {
    Movie.find(function(err, movies) {
      if (err) {
        return res.send(err);

  .post(function(req, res) {
    var movie = new Movie(req.body); {
      if (err) {
        return res.send(err);

      res.send({ message: 'Movie Added' });

Updating a Movie

If users want to update a movie, they need to send a PUT request to /api/movies/:id with a JSON string as the request body. We use the named parameter :id to access an existing movie. As we are using MongoDB, all of our movies have a unique identifier called _id. So, we just need to retrieve the parameter :id and use it to find a particular movie. The code to do this is shown below.

  Movie.findOne({ _id: }, function(err, movie) {
    if (err) {
      return res.send(err);

    for (prop in req.body) {
      movie[prop] = req.body[prop];

    // save the movie {
      if (err) {
        return res.send(err);

      res.json({ message: 'Movie updated!' });

Here, we create a new route /movies/:id and use the method put(). The invokation of Movie.findOne({ _id: }) is used to find the movie whose id is passed in the URL. Once we have the movie instance, we update it based on the JSON passed in the request body. Finally, we save this movie and send a response to the client.

Retrieving a Movie

To read a single movie, users need to send a GET request to the route /api/movies/:id. We will use the same route as above, but use get() this time.

router.route('/movies/:id').get(function(req, res) {
  Movie.findOne({ _id:}, function(err, movie) {
    if (err) {
      return res.send(err);


The rest of the code is pretty straightforward. We retrieve a movie based on the passed id and send it to the user.

Deleting a Movie

To delete a movie, users should send a DELETE request to /api/movies/:id. Again, the route is the same as above, but the method is different (i.e. delete()).

router.route('/movies/:id').delete(function(req, res) {
  }, function(err, movie) {
    if (err) {
      return res.send(err);

    res.json({ message: 'Successfully deleted' });

The method Movie.remove() deletes a movie from the database, and we send a message to the user indicating success.

Now we are all set. But wait! We need to put the router instance in the module.exports so that we can use it in our app as a middlewaree. So, this is the last line in the file movies.js:

module.exports = router;

Configuring the App

All our configurations go into app.js. We start by requiring the necessary modules:

var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var movies = require('./routes/movies'); //routes are defined here
var app = express(); //Create the Express app

The next step is connecting to MongoDB via Mongoose:

//connect to our database
//Ideally you will obtain DB details from a config file
var dbName = 'movieDB';
var connectionString = 'mongodb://localhost:27017/' + dbName;


Finally, we configure the middleware:

//configure body-parser
app.use('/api', movies); //This is our route middleware

module.exports = app;

As you can see I have used the router just like any other middleware. I passed /api as the first argument to app.use() so that the route middleware is mapped to /api. So, in the end our API URLs become:

  • /api/movies
  • /api/movies/:id


The following code goes into bin/www.js, which bootstraps our app:

var app = require('../app'); //Require our app

app.set('port', process.env.PORT || 8000);

var server = app.listen(app.get('port'), function() {
  console.log('Express server listening on port ' + server.address().port);

By running node bin/www.js, your API should be up!

Testing the API

Now that we have created the API we should test it to make sure everything works as expected. You can use Postman, a Chrome extension, to test all of your endpoints. Here are a few screenshots that show POST and GET requests being tested in Postman.

POST Testing

GET Testing


This was a basic overview of how you can create RESTful APIs easily with Node and Express. If you want to dig deeper into Express be sure to check out their docs. If you want to add or ask something please feel free to comment.

The source code for the app is available for download on GitHub.

  • Dave

    Could you explain the reasoning behind using both PUT for an update & a POST for creation?
    Why not use just POST for both?

    • Carlos

      The reason we normally do this is so we can have apropriate responses. POST should return 201 created, PUT should return 200 OK for sucess. If POST do both things then it get’s complicated.
      Besides what if you want to update a record, but got the id wrong, if POST do both things then you have just created a wrong record:)

  • Sriram

    Thanks! Would be great if you can write on how to enable authentication, preferably with an LDAP server, for these services.

  • ChristineDMcKinnis


  • Borislav

    Nice tutorial, thank you!

    The only issue I had with it, was that the “name” var in package.json wasn’t accepted as “Movie CRUD API”, I don’t know why. So I changed it to something like this “movie-crud”. I read somewhere it should be slugyfied or something.

  • Paul

    Great article, I have this running locally on POST the data doesn’t get sent only the id: is generated as with a GET method id is the only data returned.

    • Paul

      Found the issue, the input was sent as text via Postman should of been JSON format.

      • s.shivasurya

        hi sir ! i used the source from github – i ran the postmani passed the values as json format and response was success addedd

        but when i [get] queried for certain using _id it gave me only _id and v : 0
        may i know where i am going wrong ! ?[ i passed as JSON only ]

        • Brian Alexander

          same problem!

          • s.shivasurya

            @brian ! better create instance of movie and access ur posted body values and assign to it individually !
            and move inside save function in mongoose!
            i had done like that !
            however the imagining above post had got input as JSON format from client !(call using jquery ajax json as data format)

            hope u can understand!

      • daniel_zaremba

        Weird, I’ve tried JSON and no luck.
        For me it forks if I enter the values in X-www-form-urlencoded.

        Anyway, that’s why we should add soma Mocha tests :)

        Thanks for the great tutorial.

    • daniel_zaremba

      I have the same problem too, although it says “Movie Added”
      So I’m thinking it’s something to do with req.body, because that is undefined for me.

    • mmahgoub

      Seems like postman ignores send as JSON option you need to use “Headers” button at the top right to add a custom header oF Content-Type: application/json

  • Seánóg Ó Dubhshláine

    Another great tutorial. However I’m running Express/Node server on port 8000 but the Angular app on port 80. I’m getting Access-Control-Allow-Origin errors. How did you setup CORS? I’ve read lots about setting up CORS but not sure where to add the setting in the above setup?

  • Steve Cain

    Hey guys, don’t forget to set the headers in Postman, e.g. Header = Content-Type and Value =application/json. I was having the same issue where the mongo DB inserts weren’t inserting all of the data fields. Also, I changed movieCRUD/models/movie.js to title:’String’, (it has no single quotes around “String” in the GitHub source). Hope that helps.

    • Anthony Jackman

      I ran into same thing. I am glad I read your post @Steve. I had forgot about the quirk in Postman and its Headers. Although, in my source code, I left the single quotes off of the element descriptors and application still works fine.

  • Andrew G

    There is a nice framework It allows to create RESTful API very easy.

  • Adam

    Any idea how I could use in my routes? Like maybe when someone creates a new Movie I want it to be broadcasted to everyone.

  • budi
  • Charlie

    How did you avoid CSRF issues? I don’t see any middleware installed

  • ravikh

    Very nice tutorial! Was very useful.

  • shahzaib

    how to delete movie by id in postman??

  • Varo A. Benavides

    you save my ass thank you

  • mostapha

    Hello gays,

    Someone can help me please,


    // Import

    var express = require(“express”);
    var mongoose = require(‘mongoose’);
    var bodyParser = require(“body-parser”);
    var contacts = require(‘./routes/contacts’);
    var configDB = require(‘./config/database’);

    // initialize express
    var app = express();

    // connect database

    // dirname folder
    app.use(express.static(__dirname + “/public”));

    //configure body-parser

    //The route middleware
    app.use(‘/api’, contacts);

    // Port
    console.log(“Server running (port: 3000)…”);



    // Find all contacts
    router.route(‘/contacts’).get(function(req, res){
    console.log(“I received a GET request”);
    Contact.find(function(err, contacts){
    When I type http://localhost:3000/api/contacts
    I got Cannot GET /api/contacts

    Where is my problem ?

    Thanks in advance

  • Vinayak

    issue seems to be related to POSTMAN chrome plugin. Try below code

    function consume(){

    var formData = { “title”: “jurrasic”, “releaseyear”: “2015”, “director”: “ami”, “genre”: “entertain” };


    url : “http://localhost:8000/api/movies”,

    type: “POST”,

    data : formData,

    success: function(data, textStatus, jqXHR)


    //data – response from server

    console.log(“data = ” + data);

    console.log(“textStatus = ” +textStatus);

    console.log(“jqXHR = ” + jqXHR);


    error: function (jqXHR, textStatus, errorThrown)


    console.log(“errorThrown = ” );







  • focorner

    Very nice tutorial. Thank you for sharing. :) A+

  • Jag

    If any of you guys are looking for a tutorial on REST service using pure Node.js (from the scratch), I came across a beginner’s excellent video here:

  • Jag

    for the readers who are looking for a tutorial on REST service using pure Node.js (from the scratch), I came across an excellent video here:

  • Jai

    I found that there is a connet.sid being set on the client side even though there is no session. How can we remove this?


    GitHub ?


    var express = require(‘express’),

    bodyParser = require(‘body-parser’),

    app = module.exports = express(),

    allowCors = function(req, res, next) {

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

    res.header(‘Access-Control-Allow-Methods’, ‘GET,PUT,POST,DELETE’);

    res.header(‘Access-Control-Allow-Headers’, ‘Content-Type’);

    res.header(‘Access-Control-Allow-Credentials’, ‘true’);







    extended: true




Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in JavaScript, once a week, for free.