How to write containerised API using Node.js, MongoDB and Docker — Part 2

Sushrut Ashtikar
8 min readMay 7, 2019

In previous tutorial we have seen the installation process, in this tutorial we are going to create our own to do Task Api using node.js and mongob. If you are having any doubt you can refer my Git Repo from here.

Tutorial

1. Development

1.1 Setting up files and directory

  1. Open your terminal and kindly follow the following steps.
mkdir todoListApi && cd todoListApi 

2. Create a package.json file.

npm init

Package.json is a file that gives the necessary information to npm which allows it to identify the project as well as handle the project’s dependencies. npm init will prompt you to enter some information such as the app name, description, version, author, keyword and also ask if what you see is what you like.

You should have something like this eventually.

{
"name": "todolistapi",
"version": "1.0.0",
"description": "todoList Api tutorial using nodejs and mongodb",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/novasush/mongodbNodejsApi.git"
},
"keywords": [
"Nodejs",
"Mongodb",
"RestAPI",
"Docker",
"Microservices"
],
"author": "novasush",
"license": "ISC",
"bugs": {
"url": "https://github.com/novasush/mongodbNodejsApi/issues"
},
"homepage": "https://github.com/novasush/mongodbNodejsApi#readme"
}

Is this OK? (yes)

Kindly type yes and press enter to complete the creation of our package.json. Having done all these, your folder structure should look like this:

A basic structure for you project

3. Create a file called server.js

touch server.js

4. Create folder called api including three separate subfolders called models, routes, and controllers

mkdir api api/controllers api/models api/routes

5. Create todoListController.js in the api/controller folder, todoListRoutes.js in the routes folder, and todoListModel in the model folder.

touch api/controllers/todoListController.js api/models/todoListModel.js api/routes/todoListRoutes.js

Our directory structure should look like this now:

Directory structure setup as MVC pattern

1.2 Server Setup

Let’s install express and nodmon, express will be used to create the server while nodmon will help us to keep track of changes to our application by watching changed files and automatically restart the server.

npm install --save-dev nodemonnpm install express --save

On successful installation, your package.json file will be modified to have the two newly installed packages.

  1. Open the package.json file and add this task to the script
"start": "nodemon server.js"

After modification your package.json should look like this:

2. Open the server.js file and type the code below into it.

var express = require('express'),   // Import express library
app = express(), // Initialize express object in the app variable
port = 3000; // Default node port to run your api server
app.listen(port); // listening api requets on port 3000console.log('Node api server running on port ' + port); // log to check whether server running or not

3. On your terminal, run npm run start this will start the server and then you will see

> todolistapi@1.0.0 start /home/sush/rest_tutorial/todoListApi
> nodemon server.js

[nodemon] 1.19.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node server.js`
Node api server running on port 3000

1.3 Schema Setup

First of all, let’s install mongoose -

npm install mongoose --save

Why Mongoose?

Mongoose is what we will use to interact with a MongoDB(Database) instance. After installation, open the todoListModel.js file in your api/models folder and type the following code into the file and save.

'use strict';
var mongoose = require('mongoose'); // Initialize mongodb
var Schema = mongoose.Schema; //Setup schema variable here we are going to define our table
var TaskSchema = new Schema({
name: {
type: String,
required: 'You need to enter your task'
},
Created_date: {
type: Date,
default: Date.now
},
status: {
type: [{
type: String,
enum: ['pending', 'ongoing', 'completed']
}],
default: ['pending']
}
});
module.exports = mongoose.model('Tasks', TaskSchema); //Exporting task schema to task table in mongodb

From the code above, we required the mongoose in our file and then, we create a model of how our collection should look like. As you can see, it the task collection(table) will contain a name: a string, and the date it was created. It also contains task status which we have defined as pending — a default value for every task created.

1.3 Routes setup

Routing refers to determining how an application responds to a client request for a specific endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on). Each of our routes has different route handler functions, which are executed when the route is matched. Below we have defined two basic routes(‘/tasks’, and ‘/tasks/taskId’) with different methods ‘/tasks’ has to methods(‘GET’ and ‘POST’), while ‘/tasks/taskId’ has GET, PUT and DELETE. As you can see, we required the controller so each of the routes methods can call it’s respective handler function.

To do this, open the todoListRoutes.js file in the route folder and paste the code snippet below into:

'use strict';
module.exports = function(app) {
var todoList = require('../controllers/todoListController'); //Imporing our schema from model
app.route('/tasks') //Setting API endpoint for list view to get or create new task
.get(todoList.list_all_tasks)
.post(todoList.create_a_task);
/*Setting API endpoint for detail view
to get , modify or delete a specific tasks*/
app.route('/tasks/:taskId') .get(todoList.read_a_task)
.put(todoList.update_a_task)
.delete(todoList.delete_a_task);
};

1.4 Controller setup

Open todoListController.js file with your text editor( Sublime, Atom e.t.c) and let’s deep dive into coding.

In this controller, we would be writing five(5) different functions namely: list_all_tasks, create_a_task, read_a_task, update_a_task, delete_a_task. We will exported each of the functions for us to use in our routes. Each of these functions uses different mongoose methods such as find, findById, findOneAndUpdate, save and remove.

'use strict';// List View --> Get all Tasks or Create a new taskvar mongoose = require('mongoose'),
Task = mongoose.model('Tasks');
exports.list_all_tasks = function(req, res) {
Task.find({}, function(err, task) {
if (err)
res.send(err);
res.json(task);
});
};
//Detail View --> Get , Modify or Delete a specific task
exports.create_a_task = function(req, res) {
var new_task = new Task(req.body);
new_task.save(function(err, task) {
if (err)
res.send(err);
res.json(task);
});
};
exports.read_a_task = function(req, res) {
Task.findById(req.params.taskId, function(err, task) {
if (err)
res.send(err);
res.json(task);
});
};
exports.update_a_task = function(req, res) {
Task.findOneAndUpdate({_id: req.params.taskId}, req.body, {new: true}, function(err, task) {
if (err)
res.send(err);
res.json(task);
});
};
exports.delete_a_task = function(req, res) {
Task.remove({
_id: req.params.taskId
}, function(err, task) {
if (err)
res.send(err);
res.json({ message: 'Task successfully deleted' });
});
};

1.5 Putting everything together

Earlier on, we had a minimal code for our server to be up and running in the server.js file. In this section we will be connecting our handlers(controllers), database, the created models, body parser and the created routes together.

Open the server.js file created awhile ago and follow the following steps to put everything together.

Essentially, you will be replacing the code in your server.js with the code snippet from this section

  1. Connect your database by adding a url to the mongoose instance connection
  2. Load the created model — task
  3. Install bodyParser and use bodyParser Parse incoming request bodies in a middleware before your handlers, available under the req.body property. It exposes various factories to create middlewares. All middlewares will populate the req.bodyproperty with the parsed body, or an empty object ({}) if there was no body to parse (or an error was returned).
  4. Register our created routes in the server.js
var express = require('express'),   // Import express library
app = express(), // Initialize express object in the app variable
port = 3000, // Default node port to run your api server
mongoose = require('mongoose'),
Task = require('./api/models/todoListModel'), //created model loading here
bodyParser = require('body-parser');

// mongoose instance connection url connection
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/Tododb');


app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());


var routes = require('./api/routes/todoListRoutes'); //importing route
routes(app); //register the route


app.listen(port); // listening api requets on port 3000

console.log('Node api server running on port ' + port); // log to check whether server running or not

app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'}) //Incase an invalid url is specified
});

5. Start MongoDB Server as a daemon, Open your terminal and run:

mongod

This will start your MongoDB server and then, node server could connect to the MongoDB instance. Once your MongoDB server is running, restart your node server by running: rs on your nodemon running terminal.

2. Testing

We are going to use postman tool here for testing our api Now that everything is now connected, let’s test each of the routes and the respective methods.

  1. Open your postman and type: http://localhost:3000/tasks in the enter request URL section and press enter

On enter, you should see “[]” because there is nothing in the database yet.

2. On the same address, change the method to POST, click body and select “x-www-form-urlencoded”. Then, enter name as the key and the corresponding task name as value. After this, click on send button. This should give you a response 200 ok

3. Now i am going to alter an existing record, where i will be specifying a particular id in url. change the method to POST, click body and select “x-www-form-urlencoded”. Then, enter status as key and the corresponding “completed” as its value.

As you can see that, i have changed my existing status from pending to completed.

In case of issues in installation refer first part of this tutorial from here.

Click here for next part.

If you are having any doubt you can refer my Git Repo from here.

In next part we are going to containerize both node.js and mongodb server using Docker and create microservices using docker-compose.

--

--

Sushrut Ashtikar

Software Developer with over 5 years of expertise in building applications. Passionate about technology and always seeking to learn and implement new solutions.