Build a Backend With Node.js, Container and Azure (2)

Node.js is a popular a server-side framework for building high performance backend. In this post we will be looking at creating a backend API using Node, Express and Mongoose. It will handle user registration requests and publish a message to job queue.

Creating the App

Our project structure is like the following. We will keep this very simple for the demonstration purposes.

├── server.js
└── src
    ├── api.js
    └── email_service.js
├── config
│   └── config.js
├── model
│   └── user.js
├── package.json
├── docker-compose.yml
├── Dockerfile

Fist, create the package.json

npm init

This will ask you a bunch of questions, and then write a package.json for you. Now install the packages we will be using in this project.

npm install --save express mongoose body-parser amqplib

Then, we define a user model with Mongoose. Mongoose provides a schema-based way to model application data. It includes built-in type casting, validation, query building, business logic hooks and more, out of the box.

var mongoose = require(‘mongoose’);

var userSchema = new mongoose.Schema({
  email : { 
    type: String, 
    trim: true, 
    required: true, 
    index: { unique: true, uniqueCaseInsensitive: true },
    validate: {
      validator: function(v) {
            p =/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/i
            p.test(v);
        },
          message: '{VALUE} is not a valid email address!'
        }
    },
    created_at: { type: Date, default: Date.now },
  }
)

module.exports = mongoose.model('User', userSchema);

Now lets look at the api.js. In this file we define how our api responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on).
Here we has a handler function that accepts a post request, creates a new user. Once the registration has completed, it publish an email sending the job to the message queue.

app.js

app.post('/register', function(req, res) {
    var user = new User(req.body);
    user
    .save()
    .then(
        function(u) {
            email_service.send_welcome_email(u);
            return res.json({success: true})
        },
        function(err) {
            return res.status(400).json({sucess: false, data: req.body, error: err})
        }
    )
});

We will delegate the work of sending email task to the email_servie. Note the send_welcome_email is a non-block function.

email_service.js

EmailService.prototype.send_welcome_email = function(customer) {
    var self = this;

    if (self.ch) {
         process.nextTick(function() {
                 send_to_queue(self.ch, email_queue, customer.email);
         })
    } else {
        self.conn.createConfirmChannel( function(err, ch) {
            if (err) {
                return console.error(err);
            }
        self.ch = ch;
        ch.on("error", function(err) { console.error(err)});
        send_to_queue(self.ch, email_queue, customer.email)
      })
    }                                        
}

function send_to_queue(ch, q_name, content) {
    ch.publish('', q_name, new Buffer(content), { persistent: true },
        function (err, ok) {
            if (err) {
                console.error("[AMQP] publish ", err);
                pubChannel.connection.close();
            }
    })
}    

The email service publishes an email task to the message queue. In next post, we will implement a work process that picks up an email task from the message queue and sends an email out through SMTP.