Sometimes you need a backend solution that offers more than a typical Backend As A Service (BaaS) can provide, or you might want something to test against fairly quickly even if it isn’t intended to be your production server. In this post, I’m going to walk through building a server side REST API that handles CRUD operations for “messages”. To accomplish our goal, we’ll use Node.js, Express, MongoDB, and Mongoose.

Having worked on Java and Javascript client/server applications for many years, it is fun to leverage that experience to build a RESTful server for mobile apps that I’m working on. It certainly is a whole lot easier to get a server up and running than it used to be, as we’ll soon see.

The code for this project is available on my Github here.

This tutorial assumes development on MAC OS X. It is equally applicable to other operating systems with relevant installation changes.

Node.js Installation

To get started, use the Homebrew package manager to install the frameworks we need. Rather than re-invent the wheel, follow the simple instructions on the Homebrew main page here to install Homebrew. You’ll see that the installation is simple and explained right at the top of the main page.

Now we’ll install NPM, the package manager for Node, and Node itself. Type the following into the terminal:

brew install node

To check that installation was successful, you can type npm -v and node -v into the Terminal, and each command should display the version installed.

Create Node.js Application

Create a folder named restapi at your preferred location on your file system.

In the new restapi folder, create a file named server.js.

Let’s get the server up and running quickly, then we’ll add functionality to it. Add the following code to server.js.

// Create an HTTP server by loading http module var http = require('http'); // Configure the HTTP server to respond identically to any request var server = http.createServer(function (request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.end("Hello From Your HTTP Server

"); }); // Listen on port 3000, IP defaults to 127.0.0.1 server.listen(3000); // Put a friendly message on the terminal console.log("HTTP Server running at http://127.0.0.1:3000/");

To test that the HTTP server is running, cd to the restapi directory, and start the server as follows.

node server.js

To test the application, open a browser and go to http://localhost:3000. You should see the message that was specified for the response, “Hello From Your HTTP Server”

Excellent … we’ve got a server running now, so we can start enhancing it, but first let’s install MongoDB as we’ll need that before we install Mongoose.

Install MongoDB

The easiest way to install MongoDB is to use Homebrew. Simply enter the following on the command line.

brew install mongodb

Installation results in the following directories being created:

Databases: /usr/local/var/mongodb/

mongod.conf file: /usr/local/etc/mongod.conf

Mongo logs: /usr/local/var/log/mongodb/

Mongo binaries: /usr/local/Cellar/mongodb/bin

To start MongoDB, you type mongod on the command line. By default when you start the mongod process, it expects the databases to be in /data/db. Since the directories above have been created automatically, we can start MongoDB as shown below to specify where to look for database files.

mongod --dbpath /usr/local/var/mongodb/

Alternatively, you could also create the /data/db directory manually and simply run mongod without any options. The /data/db means at the root, so here are the two commands you’d need if you wish to create it there in the default location.

sudo mkdir -p /data/db sudo chown -R $USER /data/db

Once you’ve created the directory and updated permissions, then you can simply run mongod on the command line to start MongoDB. In my case, I’ve created the default directory for storing database files. Run Mongo now so it is ready.

Dependencies

Now that we’ve got MongoDB installed, we can install the other dependencies Node will need.

For a Node project, you define a package.json file to list the packages required for the project, similar to how you create a pod file for CocoaPods. Create a package.json file in the same restapi directory, with the following content.

To gain an understanding of what the versions mean and other options for specifying them, consult the documentation here and here.

{ "name": "restapi", "main": "server.js", "dependencies": { "express": "~4.13.2", "mongoose": "~4.1.0", "body-parser": "~1.13.3" } }

We’ve specified that we will need Express, Mongoose, and body-parser for our project. Express is a Node.js web framework application framework, Mongoose provides MongoDB object modelling for Node.js (like an ORM), and body-parser provides body parsing middleware for Node.js.

To load the dependencies and configure the project, enter the following from within the restapi directory.

npm install

You’ll notice that a node_modules folder is added below the restapi directory. This is where dependencies such as Express are installed, so in fact you should see a subdirectory for each of those dependencies under the node_modules directory.

REST API With Express

Using Express, we’re going to put our routes in their own file. After we do that, we’ll update server.js to use the router and defined routes.

Create a file in the root directory of the project, alongside server.js, and name this file routes.js. Add the content below to the file.

var express = require('express'); // Get the router var router = express.Router(); // Middleware for all this routers requests router.use(function timeLog(req, res, next) { console.log('Request Received: ', dateDisplayed(Date.now())); next(); }); // Welcome message for a GET at http://localhost:8080/restapi router.get('/', function(req, res) { res.json({ message: 'Welcome to the REST API' }); }); module.exports = router; function dateDisplayed(timestamp) { var date = new Date(timestamp); return (date.getMonth() + 1 + '/' + date.getDate() + '/' + date.getFullYear() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds()); }

In this file, we create the router, and add middleware handling for all requests, which in this case prints out a formatted date to the console. We accomplish this by calling a function timeLog, which includes a call to next(). We need that call so that processing continues to other routes, otherwise nothing else would happen.

We define one route, which is the root level welcome message. Now we need to tie this into server.js and use it.

Update server.js so that it contains the content below.

var express = require('express'); var app = express(); var bodyParser = require('body-parser'); var routes = require('./routes'); // express app will use body-parser to get data from POST app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); // Set port var port = process.env.PORT || 8080; // set the port // Define a prefix for all routes // Can define something unique like MyRestAPI // We'll just leave it so all routes are relative to '/' app.use('/', routes); // Start server listening on port 8080 app.listen(port); console.log('RESTAPI listening on port: ' + port);

Now run the server as usual with the command below.

node server.js

Browse to http://localhost:8080/ and you should see the message welcoming you to the REST API. Notice that the message is in JSON format as defined above in the routes.js file.

For the rest of this tutorial, I’m going to use Postman (for Google Chrome) to make requests to the REST API. For the request above, here is a screenshot of the result.

In advance of having a mobile client to interact with the RESTful server, we’ll be able to interact with it using Postman, including creating and retrieving data from the server.

Mongo Database

With some basics in place, we’ll get the database ready. First, we need to create a database. Start the Mongo console by typing mongo in the command line.

Issue the commands below one after the other. The database will be named restdb.

use restdb show dbs db.messages.save({text:"This is a sample message", user:"Anon"}) db.messages.find()

The commands above first says to Mongo to use the database named restdb. When you show dbs you don’t actually see it yet, because you first need to add a collection to it. The third command saves the first instance into the messages collection, with a text value and a user value. The last command shows the instance saved to the database. Later in the tutorial, we’ll be defining a model for our data that will contain these same two fields for a message.

We need to update server.js now to add support for connecting to the Mongo database. Update the server.js file to add the following two lines.

var mongoose = require("mongoose"); mongoose.connect('mongodb://localhost/restdb')

The resulting server.js file should now contain the code below.

var express = require('express'); var app = express(); var bodyParser = require('body-parser'); var routes = require('./routes'); var mongoose = require("mongoose"); mongoose.connect('mongodb://localhost/restdb') // Express app will use body-parser to get data from POST app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); // Set port var port = process.env.PORT || 8080; // set the port // Define a prefix for all routes // Can define something unique like MyRestAPI // We'll just leave it so all routes are relative to '/' app.use('/', routes); // Start server listening on port 8080 app.listen(port); console.log('RESTAPI listening on port: ' + port);

Now we can restart the Node.js server with node server.js. If Mongo is up and running then you should not see any errors. If it isn’t running or you’ve named the database incorrectly, you’d see a connection error. Assuming all is well, next we tackle the data model.

Data Model

Let’s create the data model for our server now. First, make a directory under the restapi directory, and name it models. Create a file in this directory and name it message.js. In the file, include the following.

var mongoose = require('mongoose'); var Schema = mongoose.Schema; var messageSchema = new Schema({ text: String, user: String }); module.exports = mongoose.model('Message', messageSchema);

We are specifying that a message object has fields named text and user.

Back in routes.js, add this one line after the code that creates the router, so that the router can use the model in our server application.

var Message = require('./models/message');

REST API Specification

The specification for the REST API we’ll expose is described below.

HTTP Method Route Description GET /messages Get all messages GET /messages/55bcf944f5cb7e0d91a1f96d Get one message for ObjectID POST /messages Create new message PUT /messages/55bcf944f5cb7e0d91a1f96d Update message for ObjectID DELETE /messages/55bcf944f5cb7e0d91a1f96d Delete message for ObjectID

We’ll implement routes that correspond to the rows in the specification table.

Retrieving All Messages

To get started with the actual REST API, let’s first implement the GET for /messages, to retrieve all messages in the database. Remember that we already have one instance of a message that we added directly via Mongo, in advance of using Mongoose and Express. Add the code below to the routes.js file, just after the router.get that returns the welcome message.

// GET all messages (using a GET at http://localhost:8080/messages) router.route('/messages') .get(function(req, res) { Message.find(function(err, messages) { if (err) res.send(err); res.json(messages); }); });

Note the usage of the find method on our modelled entity. Consult the Mongoose documentation to see all the methods available. We’ll use a few more in this tutorial. The full routes.js file should now contain the code below.

var express = require('express'); // Get the router var router = express.Router(); var Message = require('./models/message'); // Middleware for all this routers requests router.use(function timeLog(req, res, next) { console.log('Request Received: ', dateDisplayed(Date.now())); next(); }); // Welcome message for a GET at http://localhost:8080/restapi router.get('/', function(req, res) { res.json({ message: 'Welcome to the REST API' }); }); // GET all messages (using a GET at http://localhost:8080/messages) router.route('/messages') .get(function(req, res) { Message.find(function(err, messages) { if (err) res.send(err); res.json(messages); }); }); module.exports = router; function dateDisplayed(timestamp) { var date = new Date(timestamp); return (date.getMonth() + 1 + '/' + date.getDate() + '/' + date.getFullYear() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds()); }

Restart the Node server with node server.js.

Back in Postman, select the GET verb, and type in the URI as localhost:8080/messages. Click Send and you should see a JSON response showing the one message that was added to the database earlier. Here is a screenshot.

Since we’re now able to see the collection of message objects in the Mongo database, let’s add support for creating new messages.

Creating A Message

Now that you’ve seen how to use routes and the data model by retrieving messages, the rest of the REST API implementation should be fairly straightforward. Add the code below to the routes.js file, after the previous route for retrieving all messages.

// Create a message (using POST at http://localhost:8080/messages) router.route('/messages') .post(function(req, res) { var message = new Message(); // Set text and user values from the request message.text = req.body.text; message.user = req.body.user; // Save message and check for errors message.save(function(err) { if (err) res.send(err); res.json({ message: 'Message created successfully!' }); }); });

With the new route in place, let’s create a message. Restart the server with node server.js. Go to Postman, and select the POST verb. Click on the Body tab to enter Key/Value pairs corresponding to text and user data. Make sure you also select x-www-form-urlEncoded for the type of body, which is the default content type for simple ASCII text (versus binary and non-ASCII). Enter a key value of text, and enter a value of “Hey there, just saying hello!“. Enter a key of user, and a value that is your name, so “lawrence” in my case. Click Send. You should see the JSON response that we defined in the route; “message”: “Message created successfully!”.

At this point, you can use the previously implemented GET for retrieving all messages to check the messages in the database. Send that request again and confirm that there are now two messages in the database. You’ll notice that there is an extra data field in the response, which looks like “__v”: 0. Not to worry though as this is a version key inserted automatically by Mongoose.

Viewing Data in MongoDB

At this point it would be worthwhile to talk about viewing the data in MongoDB so that we can compare what is there to what is returned via our REST API. There are various applications for this purpose, but I’m using Robomongo for OS X. You can download it here. Over the years I’ve used a number of tools for managing various databases on Windows and OS X, and I’m pleased with what Robomongo has to offer on OS X.

Once you download it, connect to your restdb database and you can browse the messages collection to see the data.

Retrieving One Message

Let’s implement a route for retrieving one message based on the ObjectID of the message. Add the code below to the routes.js file after the previous route.

// GET message with id (using a GET at http://localhost:8080/messages/:message_id) router.route('/messages/:message_id') .get(function(req, res) { Message.findById(req.params.message_id, function(err, message) { if (err) res.send(err); res.json(message); }); });

Stop and restart the Node server.

In Postman, send a GET request with the URL localhost:8080/messages/<id>, where the value for <id> is one of the _id values for messages retrieved via the GET request we defined for retrieving all messages. You should see the response in Postman for the one specific message object.

Updating A Message

Let’s implement support for updating a given message. Enter the code below into the routes.js file.

// Update message with id (using a PUT at http://localhost:8080/messages/:message_id) router.route('/messages/:message_id') .put(function(req, res) { Message.findById(req.params.message_id, function(err, message) { if (err) res.send(err); // Update the message text message.text = req.body.text; message.save(function(err) { if (err) res.send(err); res.json({ message: 'Message successfully updated!' }); }); }); });

Restart the Node server, then in Postman select the PUT verb, and enter just a key of text, and an updated value of “Saying hello again!“. Enter the URI localhost:8080/messages/<id>, where the <id> is the same one you entered in the previous section to retrieve a single message. Click Send and you should see the “Message successfully updated!” JSON response. With Robomongo you can look at the record in the database to verify the update, and you can also issue another GET request from Postman to verify the update value.

We’ve now implemented the first 4 of 5 planned API calls for our REST API. Let’s do the last one now, the ability to delete messages.

Delete Message

Add the following code to the routes.js to handle the delete of a message.

// Delete message with id (using a DELETE at http://localhost:8080/messages/:message_id) router.route('/messages/:message_id') .delete(function(req, res) { Message.remove({ _id: req.params.message_id }, function(err, message) { if (err) res.send(err); res.json({ message: 'Successfully deleted message!' }); }); });

Restart the server, and in Postman using the same URI from the previous section, change the verb to be DELETE. Click Send and you should see the success JSON response. Check in one or both of Robomongo and Postman by using the API call for retrieving all messages, and you should see one message is now deleted.

Chaining Routes

You can implement the routes such that those with the same URL are chained. Take a look at the updated routes.js below to see how the three API calls that have message_id are chained together under one router.route(‘/messages/:message_id’).

var express = require('express'); // Get the router var router = express.Router(); var Message = require('./models/message'); // Middleware for all this routers requests router.use(function timeLog(req, res, next) { console.log('Request Received: ', dateDisplayed(Date.now())); next(); }); // Welcome message for a GET at http://localhost:8080/restapi router.get('/', function(req, res) { res.json({ message: 'Welcome to the REST API' }); }); // GET all messages (using a GET at http://localhost:8080/messages) router.route('/messages') .get(function(req, res) { Message.find(function(err, messages) { if (err) res.send(err); res.json(messages); }); }); // Create a message (using POST at http://localhost:8080/messages) router.route('/messages') .post(function(req, res) { var message = new Message(); // Set text and user values from the request message.text = req.body.text; message.user = req.body.user; // Save message and check for errors message.save(function(err) { if (err) res.send(err); res.json({ message: 'Message created successfully!' }); }); }); router.route('/messages/:message_id') // GET message with id (using a GET at http://localhost:8080/messages/:message_id) .get(function(req, res) { Message.findById(req.params.message_id, function(err, message) { if (err) res.send(err); res.json(message); }); }) // Update message with id (using a PUT at http://localhost:8080/messages/:message_id) .put(function(req, res) { Message.findById(req.params.message_id, function(err, message) { if (err) res.send(err); // Update the message text message.text = req.body.text; message.save(function(err) { if (err) res.send(err); res.json({ message: 'Message successfully updated!' }); }); }); }) // Delete message with id (using a DELETE at http://localhost:8080/messages/:message_id) .delete(function(req, res) { Message.remove({ _id: req.params.message_id }, function(err, message) { if (err) res.send(err); res.json({ message: 'Successfully deleted message!' }); }); }); module.exports = router; function dateDisplayed(timestamp) { var date = new Date(timestamp); return (date.getMonth() + 1 + '/' + date.getDate() + '/' + date.getFullYear() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds()); }

You can try running all the requests again using this new code and see the same results. In the project checked into Github, routes.js matches this updated version. I’ve included the original version as routes_original.js just for clarity.

Conclusion

The functionality in the Node-based server project is obviously the tip of the iceberg in terms of what can be done. Hopefully though, this gives you a good introduction into how a server can be up and running fairly quickly as a backend for a mobile app. The server can be deployed to a cloud application platform such as Heroku quite easily.

If you have any questions, comments, or general feedback, please leave a comment or drop me an email.