Node.js
Posted By Sebastian

Angular 6 – MEAN Stack Crash Course – Part 2: Implementing The Back-end


Subscribe On YouTube

DemoCode

Part 1: Front-end Project Setup And Routing
Part 2: Implementing The Back-end
Part 3: Connecting Front-end To Back-end
Part 4: Completing The User Interface

In the first part of this MEAN Stack Crash Course series we’ve started to build the Angular 6 front-end application. In this second part we’ll now focus on building the back-end of the MEAN Stack application by using Node.js, Express, MongoDB. You’ll also learn the following:

  • Setting up and running MongoDB
  • Implementing the back-end API with Node.js and Express.js
  • Connect the back-end server to the MongoDB database by using Mongoose
  • Use Postman for testing the server API

Again, in the following you can see the main building blocks of the MEAN stack application:

Let’s get started …


If you like CodingTheSmartWay, then consider supporting us via Patreon. With your help we’re able to release developer tutorial more often. Thanks a lot!


Setting Up The Back-end Project

To create a new Node.js project let’s first create a new empty back-end project directory:

$ mkdir backend

Change into the new directory

$ cd backend

and then initialize the a new package.json file by using the npm command:

$ npm init -y

Setting Up Babel

In order to be able to use ES6 features in our Node.js code we need to set up the Babel compiler for our project. Enabling Babel is very easy, first you need to install the packages babel-cli and babel-preset-env via NPM:

$ npm install --save-dev babel-cli babel-preset-env

Once installed you need to add a .babelrc file to the project and add the content:

{
  "presets": ["env"]
}

Now we’re ready to use the Babel compiler for the project.

Installing babel-watch

Starting the Babel compiler manually after every code change would be inconvenient. By using babel-watch we can automate this task and in addition making sure that the Node.js web server process is restarted as well. Let’s add babel-watch as a dependency to our project:

$ npm install babel-watch --save-dev

Then use babel-watch in your package.json file in scripts section like this:

"scripts": {
    "dev": "babel-watch server.js"
  }

Later on, when we’ve implemented the server in file server.js this will enable us to start the server by using the following command:

$ npm run dev

This command will then execute babel-watch which starts the Node.js server and makes sure that the Babel tarnspiler is running in watch mode as well. Everytime the implementation is changed the compilation is done automatically and the Node.js server is restarted again, so that everything is updated without needed to perform manual steps.

Installing Express

Because we’d like to use the Express framework for implementing the server we’re installing the corresponding package first:

$ npm install express

Furthermore we need to make sure that the mongoose library is available, so that we’re able to use that library to access the MongoDB database:

$ npm install mongoose

Furthermore we’re installing the cors package:

$ npm install cors

The package contains a middleware for the Express server, so that you can enable CORS (Cross-Origin Resource Sharing). CORS is a system, consisting of transmitting HTTP headers, that determines whether to block or fulfill requests for restricted resources on a web page from another domain outside the domain from which the resource originated.
The same-origin security policy forbids “cross-domain” requests by default. CORS gives web servers cross-domain access controls, which enable secure cross-domain data transfers.

Implementing The Server

Implementing A Basics Node.js/Express Server

To be able to implement the server we first need to add a new file server.js to our project:

$ touch server.js

Next, you can open up this file in your favorite text editor and add the following code:

import express from 'express';

const app = express();
app.get('/', (req, res) => res.send('Hello World!'));
app.listen(4000, () => console.log(`Express server running on port 4000`));

Start the server process by executing

$ npm run dev

You should now be able to see the following output on the command line:

If you’re now accessing http://localhost:4000 in the brower you should be able to see the following output:

Extending The Server Implementation

Now that we have a first basic Node.js/Express server implemented and running we can continue to extend the server implementation further. The Node.js server should act as the back-end of our MEAN stack application and therefore needs to offer various end points. The following use cases must be covered:

  • Process an HTTP GET request to retrieve a list of all issues from the MongoDB database
  • Process an HTTP GET request to retrieve a single issue by ID from the MongoDB database
  • Process an HTTP POST request to insert a new issue in the MongoDB database
  • Process an HTTP POST request to update an existing issue entry in the MongoDB database
  • Process an HTTP GET request to delete an existing issue entry from the database

In the first step let’s extend the server implementation in server.js with the following code:

import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';

const app = express();
const router = express.Router();

app.use(cors());
app.use(bodyParser.json());

mongoose.connect('mongodb://[server]/issues');

const connection = mongoose.connection;

connection.once('open', () => {
    console.log('MongoDB database connection established successfully!');
});

app.use('/', router);

app.listen(4000, () => console.log(`Express server running on port 4000`));

Because we’ll be dealing with Issue objects, let’s first add a data model for that entity to our application by using the Mongoose library. Create a new folder inside the back-end project named models and create a new file Issue.js to insert the following code:

import mongoose from 'mongoose';

const Schema = mongoose.Schema;

let Issue = new Schema({
    title: {
        type: String
    },
    responsible: {
        type: String 
    },
    description: {
        type: String
    },
    severity: {
        type: String
    },
    status: {
        type: String,
        default: 'Open'
    }
});

export default mongoose.model('Issue', Issue);

By using this code, we’re creating a new Mongoose model for the issue entity with the following properties included:

  • title
  • responsible
  • description
  • severity
  • status

The model is created by defining a new Schema first and then creating the model by using the mongoose.model method. The model is exported, so that we’re able to import it again in server.js by adding the following import statement:

import Issue from './models/Issue';

Retrieving All Issues

We’ve already created the Express Router instance which is available via router. To configure and implement the various endpoints of the server we can now make use of Router’s route method. First let’s add the /issues route by inserting the following piece of code into server.js:

router.route('/issues').get((req, res) => {
    Issue.find((err, issues) => {
        if (err)
            console.log(err);
        else
            res.json(issues);
    });
});

By calling the get method on the returned Route object we’re registering an event handler function which is called each time a HTTP GET request is send to this route. Inside that function we’re making use of the Mongoose model Issue to call the find method to retrieve all issues available in the database. We’re passing in another function which is invoked once the result from the database is available.

If an error has occurred (the err parameter is available) the error is printed on the console. If no error has occurred the list of issues is returned in JSON format.

Retrieving An Issue By ID

The next route which is added is /issues/:id. This route is used to send a HTTP GET request to retrieve a single issue from the database in JSON format. Part of that route is the id parameter. This parameter is used to specify which issue entry should be returned. Add the following piece of code to the implementation in server.js:

router.route('/issues/:id').get((req, res) => {
    Issue.findById(req.params.id, (err, issue) => {
        if (err)
            console.log(err);
        else
            res.json(issue);
    })
});

To retrieve a single entry via the Mongoose model we’re using the method findById. The value from the id route parameter can be accessed via req.params.id and is passed as the first parameter to findById.

Adding New Issues

The route which is used to add new issues via an HTTP post request is /issues/add. With the data submitted in the request body (available via req.body) we’re creating a new Issue object. The save method from the model class is then used to store this new Issue object in the database.

router.route('/issues/add').post((req, res) => {
    let issue = new Issue(req.body);
    issue.save()
        .then(issue => {
            res.status(200).json({'issue': 'Added successfully'});
        })
        .catch(err => {
            res.status(400).send('Failed to create new record');
        });
});

Updating Issues

The code which needs to added to update existing issues by sending an HTTP Post request to route /issues/update/:id can be seen in the following listing:

router.route('/issues/update/:id').post((req, res) => {
    Issue.findById(req.params.id, (err, issue) => {
        if (!issue)
            return next(new Error('Could not load Document'));
        else {
            issue.title = req.body.title;
            issue.responsible = req.body.responsible;
            issue.description = req.body.description;
            issue.severity = req.body.severity;
            issue.status = req.body.status;

            issue.save().then(issue => {
                res.json('Update done');
            }).catch(err => {
                res.status(400).send('Update failed');
            });
        }
    });
});

First the findById method is used to retrieve the issue which should be updated from the database. Once the issue object is available the data fields are updated with the values included in the request body. The update issue object is then stored in the database by calling method save.

Deleting Issues

Next, let’s add the route /issues/delete/:id to delete an existing issue entry from the database:

router.route('/issues/delete/:id').get((req, res) => {
    Issue.findByIdAndRemove({_id: req.params.id}, (err, issue) => {
        if (err)
            res.json(err);
        else
            res.json('Removed successfully');
    });
});

To delete an entry by it’s identifier the method findByIdAndRemove is used. This method is expecting to get two parameters:

  • As the first parameter an object is passed in containing the property _id. As the value we’re assigning the identifier of the issue which should be deleted. This value is available via the route parameter id, so that we’re able to access it via req.params.id.
  • The second parameter is a call-back method which is invoked once the request to delete the entry from the database has been processed.

Finally, let’s take a look at the complete code in server.js:

import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';

import Issue from './models/Issue';

const app = express();
const router = express.Router();

app.use(cors());
app.use(bodyParser.json());

mongoose.connect('mongodb://[server]/issues');

const connection = mongoose.connection;

connection.once('open', () => {
    console.log('MongoDB database connection established successfully!');
});

router.route('/issues/add').post((req, res) => {
    let issue = new Issue(req.body);
    issue.save()
        .then(issue => {
            res.status(200).json({'issue': 'Added successfully'});
        })
        .catch(err => {
            res.status(400).send('Failed to create new record');
        });
});

router.route('/issues').get((req, res) => {
    Issue.find((err, issues) => {
        if (err)
            console.log(err);
        else
            res.json(issues);
    });
});

router.route('/issues/:id').get((req, res) => {
    Issue.findById(req.params.id, (err, issue) => {
        if (err)
            console.log(err);
        else
            res.json(issue);
    })
});

router.route('/issues/update/:id').post((req, res) => {
    Issue.findById(req.params.id, (err, issue) => {
        if (!issue)
            return next(new Error('Could not load Document'));
        else {
            issue.title = req.body.title;
            issue.responsible = req.body.responsible;
            issue.description = req.body.description;
            issue.severity = req.body.severity;
            issue.status = req.body.status;

            issue.save().then(issue => {
                res.json('Update done');
            }).catch(err => {
                res.status(400).send('Update failed');
            });
        }
    });
});

router.route('/issues/delete/:id').get((req, res) => {
    Issue.findByIdAndRemove({_id: req.params.id}, (err, issue) => {
        if (err)
            res.json(err);
        else
            res.json('Removed successfully');
    });
});

app.use('/', router);

app.listen(4000, () => console.log(`Express server running on port 4000`));

Setting Up MongoDB

Now that we’ve fully implemented the Node.js / Express server we need to set up MongoDB on our local system to make sure that a connection to the database can be established. MongoDB is a fee and open-source document-based database. It stores data in flexible, JSON-like documents, meaning fields can vary from document to document and data structure can be changed over time. The project’s website can be found at: https://www.mongodb.com.

The installation procedure of MongoDB depends on your operating system. You can find detailed instructions at https://docs.mongodb.com/manual/administration/install-community/.

The following installation steps assume that you’re using MacOS as your operating system.

The installation on MacOS can be done by using Homebrew (https://brew.sh/).

First use the following command to make sure that Brew is up to date:

$ brew update

After that perform the MongoDB installation by using the brew command in the following way:

$ brew install mongodb

Create a data directory:

$ sudo mkdir -p /data/db

And make sure that the data directory is fully accessible with the user under which the MongoDB database process is started:

$ sudo chown [username] /data/db

Finally start the MongoDB database server by using the following command:

$ mongod

Using Robo 3T

Once the MongoDB database is running we need to create the issues collection and insert some sample issues. The easiest way to do so is to use a lightweight MongoDB GUI like Robo 3T which can be downloaded for free from https://robomongo.org:

Starting The Node.js Server

Finally we’re ready to start up the Node.js server by entering the following command within the backend directory:

$ npm run dev

You should then be able to see the following output which confirms that everything is running without problems:

Testing The Server With Postman

Now all prerequisites are in place: MongoDB is running, the Node.js server has been started successfully and the connection to the MongoDB database has been established successfully. Furthermore the issues collection has been created and sample data records have been inserted.

To test the end points of the server we just need to send corresponding HTTP requests. This can be done by using a tool like Postman (https://www.getpostman.com):

By using Postman you are able to send any kinds of HTTP request to server endpoints and see the result in detail:

What’s Next

In this part of the MEAN stack crash course series we’ve completed the back-end of the application by using MongoDB, Node.js and Express.

In the next part we’re going to continue the implementation of the Angular 6 front-end application. To connect to the back-end we’re going to implement an Angular service which will be used within our components.

ONLINE COURSE: Angular & NodeJS - The MEAN Stack Guide

Check out the great online course Angular & NodeJS – The MEAN Stack Guide with thousands of students already enrolled:

Angular & NodeJS – The MEAN Stack Guide

  • Learn how to connect your Angular Frontend to a NodeJS & Express & MongoDB Backend by building a real Application
  • Connect any Angular Frontend with a NodeJS Backend

  • Use ExpressJS as a NodeJS Framework
  • Improve any Angular (+ NodeJS) application by adding Error Handling
  • Understand how Angular works and how it interacts with Backends

  • Use MongoDB with Mongoose to interact with Data on the Backend

Go To Course

ONLINE COURSE: Angular - The Complete Guide

Check out the great Angular – The Complete Guide with thousands of students already enrolled:

Angular – The Complete Guide

  • This course covers Angular 6
  • Develop modern, complex, responsive and scalable web applications with Angular
  • Use their gained, deep understanding of the Angular  fundamentals to quickly establish themselves as frontend developers
  • Fully understand the architecture behind an Angular application and how to use it
  • Create single-page applications with on of the most modern JavaScript frameworks out there

Go To Course


Using and writing about best practices and latest technologies in web design & development is my passion.