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.