Professional Application Development in MEAN Stack - Part 4
Date Published: 03/17/2018
In the previous part, we created the Contact Us page by using Angular reactive form, implemented the client side validation and created DataService to send the user information from Contact Us page to the server side. In this part, we will implement the server side code in Node.js to take the user information and email it to the admin.

Download Source on GitHub

Introduction

So in previous part, we developed the Contact Us page and helping classes in Angular that is our client side. In order to email the Contact Us page information, we need some server-side application that we are going to develop in this part using Node.js. 

There are a lot of Node.js tutorials available online so I don't want to write redundant information, though I will briefly explain each step but its better reading some of the Node.js tutorials online before starting this article. 

Let's Start

  1. Please go through previous parts before reading this one and download the part 3 from Github, this part already has the Node.js server-side project. You can just delete it if you want to follow along with me. 
  2. Once you clone/download the part 3, open the project in Visual Studio Code, you would already have the mazharncoweb folder containing Angular client-side project. Create a new folder name server on the same level as mazharncoweb
  3. In the bottom TERMINAL panel, write the command: cd server to get into new server folder, after that run command: npm init. It will ask you a couple of questions, enter the following answer to the required questions:
    1. Package Name: server
    2. Entry Name: mazharnco.js
    3. Leave rest of the information or enter whatever you think is better.
    4. In the end, type yes for the question, Is this ok?
    5. So what we just did is created the package.json file in server folder that will contain all references to our packages and entry point of our application. If you already worked in Node.js or read about it, you may know that Node.js itself is a quite slim library so we need to add lot more packages to create our application. e.g. we will use Express.js framework that is used to create RESTful APIs in Node.js, nodemailer to send an email etc.
  4. Next, let's download all Node.js packages that we will use in our development and understand their purpose, open the bottom TERMINAL and run the commands on by one:
    1. npm install nodemailer --save : The nodemailer is used to send an email.
    2. npm install express --save: Express.js is a node.js web application framework that we would use to write the RESTful APIs.
    3. npm install ejs --save: EJs is a template engine works with Express.js, what it does to convert JavaScript into HTML and send it to the client, simple.
    4. npm install cors --save: To enable CORS. Since our client and server may be on different domain e.g. client can be on http://xyz.com and server may be on http://abc.com. If a client wants to call any GET API or send data through POST API, this is normally not possible due to security reasons. CORS package makes it enable with our custom defined rules. 
    5. npm install body-parser --save: When we call POST API from a client like we are sending Contact Us information in previous part, we are sending data in the request's body, that only would be able to read in Express.js APIs by the body-parser package.
    6. npm install pm2 -g: PM2 is a simple process manager to start, stop, restart, show a status of the Node.js application. We will use it for the same purpose and just like we learned environment-specific build for Angular application, here we will run Node.js application environment-wide. 
  5. Alright, hopefully, you have downloaded all required packages and now you have node_modules folder in your main folder server, now let's start development. 
  6. First, let's create the email.js file where we will write code to send an email. Create the new folder shared in server folder, right click on it, select the option New File, enter the file name email.js. Add following code in it: 
    const nodemailer = require('nodemailer');
    
    module.exports.sendEmail = function (to, bcc = "", subj, msg, html, callback) {
        var transporter = nodemailer.createTransport({
            service: process.env.EMAIL_SERVICE,
            auth: {
                user: process.env.ADMIN_EMAIL,
                pass: process.env.ADMIN_EMAIL_PW
            }
        });
    
        var mailOptions = {
            from: '"Mazhar & Co. "<"'+process.env.FROM_EMAIL+'">',
            to: to,
            bcc: bcc,
            subject: subj,
            text: msg,
            html: html
        };
    
        return transporter.sendMail(mailOptions, callback);
    }
    
    ​
  7. Pretty straightforward code, we are using nodemailer package that we have installed earlier, if you go to their official website link, we are using code from there. The sendEmail is a function with to, optional bcc, subj, msg, HTML msg and the callback function. All are self-explanatory and if you read about Node.js, you would learn that Node.js function has the callback function, that is called when function execution is done, so this feature helps Node.js application to not wait for function completion and move control to the next function. The nodemailer also support callback, that's why we are passing a callback function as a parameter so that when nodemailer is done sending an email, it returns us information in callback e.g. successful or failure response. We will write this callback function in contact POST API. We will learn the complete flow when developing the contact POST function.
  8. The important thing you can see is the process.env, we will create environment file and run Node.js application with pm2 specifying that environment file so that it can replace process.env variables with the right environment values.
  9. Create a new folder model in server folder, right click on it and select New File, enter the name of the file as contactMdl.js. This would be our model class where we will have same Contact Me form attributes with validation when we will use MongoDB database. Right now, we will only have one function to send an email to the admin. Edit the contactMdl.js file and add following code: 
    const emailer = require('../shared/email');
    const Contact = module.exports;
    
    module.exports.sendContactEmail = function (name, email , message,callback) {
      let msgplain =  name + ' has sent you a message '+ email +'-'+ message;
      let msghtml =  name + ' has sent you a message <br>'+'Email Address: '+email+'<br><br>Message: '+ message;
      emailer.sendEmail(process.env.FROM_EMAIL,'', 'New Message Received from Mazhar & Co.', msgplain, msghtml,callback);
    }​
  10. So in the first line, we are adding email.js reference we created in the previous step. We are creating a sendContactEmail function, exporting it so that can be accessed. Here we are creating two kinds of messages, one is plain text whereas second is HTML so it can be accessed on both kind of devices who has HTML support and one who doesn't. The last parameter is the callback function that we are sending as it is receiving from function parameters. Admin email address is loading from environment file that we would create in upcoming steps.
  11. Next, let's create a contact Restful API to receive the contact information from the Angular client and email it to the admin. Create a routes folder in server and then create a new file contact.js in it. Add following code in it:  
    const express = require('express');
    const router = express.Router();
    const Contact = require('../models/contactMdl');
    
    router.post('/contact', function (req, res) {
      Contact.sendContactEmail(req.body.Name, req.body.EmailAddress, req.body.Message,
        function (error, info) {
          if (error) {
            res.json({ success: false, msg: error });
          } else {
            res.json({ success: true, msg: "Thank you for contacting, we will get you back soon!" });
          }
        }
      );
    });
    
    module.exports = router;
    ​
  12. We created this file in routes folder because in Express.js routing is the way how application endpoints or URI (RESTful API addresses)respond to the clients requests. You can see we have one POST request with the /contact route path and next statement is a function that has req and res parameters. This function is called route method and it is derived from HTTP methods. It has request object that is actually the contact object we are sending from an Angular client application in POST request's body. Please go to Angular DataService class and see how we are creating POST request. Next, we are calling a sendContactEmail method and passing contact object values as parameters. The last parameter is a callback function that we are sending as a parameter named callback. When nodemailer sends an email, it returns the response in error and info variables that we can use to determine the success or failure response. We are checking here if there is an error, send an error message to the user otherwise send a thank you message. (You should send a custom error message to the user too, I am just sending error as it is to explain it)
  13. Read more about Express Routing.
  14. Next, let's add our entry point or main javascript file. Create a new file in a server folder named mazharnco.js and add the following code:  
    const express = require('express');
    const path = require('path');
    const bodyParser = require('body-parser');
    const cors = require('cors');
    const contacts = require('./routes/contact');
    
    var app = express();
    
    app.engine('html', require('ejs').renderFile);
    app.use(express.static(path.join(__dirname, './views')));
    
    app.use(bodyParser.urlencoded({ extended: false }))
    app.use(bodyParser.json())
    app.use(cors());
    app.use("/api", contacts);
    
    app.get('*', function (req, res) {
        res.render(path.join(__dirname, './views/index.html')); // load our public/index.html file
    });
    
    const port =  process.env.PORT;
    
    app.listen(port, function () {
        console.log('Server started on port ' + port);
    });​
  15. So here you would see all packages in action that we installed earlier. Let's briefly understand the code.
    1. In first five lines, we are creating the module objects of Express.js, Path, Body Parser, CORS and our own created Contact route. We already learned about each package in previous steps.
    2. Next line var app = express() is important, the app usually represents the Express application that we are creating from express() function of the express module. The app object has different methods e.g.
      1. routing HTTP requests (GET, POST, PUT, DELETE etc.).
      2. Configuring middleware: Middleware function has req, res objects and next() function to move to next middleware, more like you can interrupt any function, add functionality and move to the rest of the implementation. 
      3. Rendering HTML views
      4. Registering template engine: Like we are going to use Ejs to render our HTML.
    3. Express.js has a very important concept called middleware, so let's learn about it before moving further: 
      1. Middleware functions have access to Request, Response objects and next() function in request-response cycle. Through middleware, you can change the request e.g. any validation and also can update response object before sending to the client. There can be many middleware functions in one method and we use next() function to jump to next one. So in simple words, just consider middleware function sitting between request and response and can do anything before going to request or sending the response back to the requestor.
    4. In next statement app.engine('html', require('ejs').renderFile);, we are mapping Ejs template engine to HTML files, since we are writing code in Angular when it would be built, it would spit out HTML. The ejs template engine is good for that HTML rendering. 
    5. In app.use(express.static(path.join(__dirname, './views')));, we are using app.use that mounts the middleware function and basically telling to take the static files from views folder. We would put Angular build (created by ng build --prod command) in views folder. The Angular build will have one index.html file, when we would request, http://......../index.html, its path would be matched and index.html static file would be returned by this statement.
    6. Next two statements app.use(express.staticapp.use(bodyParser.urlencoded({ extended: false })); and app.use(bodyParser.json()); are also with app.use that again mounts middleware to enable us to read the request body. Go to routes -> contact's POST function, you can see we are using req.body.name, req.body.EmailAddress etc. these statements are not possible without using bodyParser
    7. The app.use(cors()); is making it possible to call the APIs from a different domain. You can explore it more to implement specific rules according to your application (security) requirements.
    8. In app.use("/api", contacts);, we are actually mounting middleware on contacts APIs. E.g. go to contact.js and check the POST call, our path is '/contact'. This middleware is simply appending "/api" path to this POST call path. So final path to the contact POST API call would be http://........./api/contact
    9. In next statement app.get('*'....), we are telling our application if the user tries to access an unknown page, just redirect it to the index.html page from views folder.
    10. In next statement, we are getting the port from environment file.
    11. The app.listen would open the connection and start listening to the request on the specified port.
  16. In the end, let's create environment file we keep talking from starting of this article, create new file environment.json in server folder and add following code in it:  
    {
        "apps": [
            {
                "name": "mazharnco",
                "script": "./mazharnco.js",
                "watch": true,
                "env": {
                    "NODE_ENV": "development",
                    "ADMIN_EMAIL":"XXXXXX@XXXX.com",
                    "ADMIN_EMAIL_PW":"",
                    "EMAIL_SERVICE":"Gmail",
                    "FROM_EMAIL":"XXXXXX@XXXX.com",
                    "PORT":"3000"
                },
                "env_production": {
                    "NODE_ENV": "production",
                    "ADMIN_EMAIL":"XXXX1@XXX1.com",
                    "ADMIN_EMAIL_PW":"",
                    "EMAIL_SERVICE":"Gmail",
                    "FROM_EMAIL":"XXXXX1@XXXX1.com",
                    "PORT":"5001"
                }
            }
        ]
    }​
  17. just go through above file, we are specifying the application name and entry script mazharnco.js that is our main/entry javascript file. We have two JSON object with the same variables name but different value. 
  18. Go to the Angular project by running the command in the TERMINAL: cd mazharncoweb and then build it by ng build --prod command.
  19. It will take few seconds and finally you would see dist folder in mazharncoweb, copy its content and go to the server folder. Create a folder views in there and paste the copied content in it.
  20. Since we are using pm2 as our process manager and to run Node.js application, In TERMINAL, run the command: pm2 start environment.json
  21. Now, go to the browser and open the URL: http://localhost:3000 because in our environment.json file, we specified 3000 port for development. Check PM2 Github page for all commands. 

Keywords: Angular Reactive Form tutorial, Node.js nodeemailer, MEAN stack tutorial, Angular 5 tutorial for beginners, MEAN Stack tutorial for beginners, Rxjs tutorial or beginner, Rxjs vs Promise,nodemailer,pm2