Like any kind of apps, there are difficult issues to solve when we write Node apps.
In this article, we’ll look at some solutions to common problems when writing Node apps.
Using Mongoose Promises with async/await
Mongoose methods return promises.
So we can use them with async
and await
.
For instance, we can write:
const orderEmployees = async(companyID) => {
try {
const employees = await User.find({ company: companyID }).exec();
console.log(employees);
return employees;
} catch (err) {
return 'error occured';
}
}
We can User.find
with a query.
That returns a promise with the resolved result.
We can also catch errors with catch
.
Pass Variable to HTML Template in nodemailer
Nodemailer accepts HTML for content.
To make creating HTML emails easier, we can use a templating engine like Handlebars.
For instance, we can write:
const nodemailer = require('nodemailer');
const smtpTransport = require('nodemailer-smtp-transport');
const handlebars = require('handlebars');
const path= require('path');
const fs = require('fs');
const readHTMLFile = (path, callback) => {
fs.readFile(path, {
encoding: 'utf-8'
}, (err, html) => {
if (err) {
throw err;
callback(err);
} else {
callback(null, html);
}
});
};
smtpTransport = nodemailer.createTransport(smtpTransport({
host: mailConfig.host,
secure: mailConfig.secure,
port: mailConfig.port,
auth: {
user: mailConfig.auth.user,
pass: mailConfig.auth.pass
}
}));
readHTMLFile(path.join(__dirname, '/template.html'), (err, html) => {
const template = handlebars.compile(html);
const replacements = {
username: "joe"
};
const htmlToSend = template(replacements);
const mailOptions = {
from: 'from@email.com',
to: 'to@email.com',
subject: 'test',
html: htmlToSend
};
smtpTransport.sendMail(mailOptions, (error, response) => {
if (error) {
console.log(error);
callback(error);
}
});
});
We import the Handlebars library and call compiler
with the template.
The template is read from the readHTMLFile
function which uses fs
to read the file.
Then it’s passed to the callback.
We get the template with the html
parameter.
Once we compile the template, we call template
with the object with the properties to interpolate the properties into the template to get the final email.
Then we call smptTransport.sendMail
to send the email.
We set the html
property with the HTML content.
htmlToSend
is an HTML string.
Formatting ISODate from MongoDB
We can format the date object from MongoDB with the toTimeString
method.
We just call ut by writing:
const date = new Date("2019-07-14T01:00:00+01:00")
consr str = date.toTimeString();
MongoDB also has the ISODate
function to make working with ISO date strings easy.
For example, we can write:
ISODate("2019-07-14T01:00:00+01:00").toLocaleTimeString()
to parse the ISO date string and convert it to a locale-sensitive time string.
We can also get the hours and minutes:
ISODate("2019-07-14T01:00:00+01:00").getHours()
ISODate("2019-07-14T01:00:00+01:00").getMinutes()
Stub Node.js Built-in fs During Testing
We want to mock the fs
module so that tests won’t do real file operations.
To do that, we use rewire
to stub out required modules.
For instance, if our real code is:
reader.js
const fs = require('fs');
const findFile = (path, callback) => {
fs.readdir(path, (err, files) => {
//...
})
}
We can use rewire
to stub out readdir
in our test code by writing:
const rewire = require('rewire')
const `reader` = rewire('./`reader`')
const fsStub = {
readdir(path, callback){
callback(null, [])
}
}
`reader`.__set__('fs', fsStub)
`reader`()
Now we can use reader
without actually calling readdir
since we called __set__
to set the fs
module to our stub instead of the read fs
module.
Return Updated Collection with Mongoose
We can return an updated collection in Mongoose, then we can get it from findOneAndUpdate
with the new
option set to true
.
For instance, we can write:
Model
.findOneAndUpdate({
user_id: data.userId
}, {
$set: {
session_id: id
}
}, {
"new": true
})
.exec()
.then(data => {
return {
sid: data.session_id
}
})
We call findOneAndUpdate
and then we use $set
to update a field,
We pass in an object with the new
property set to true
to return the latest data in the then
callback.
Also, we can write:
Lists.findByIdAndUpdate(listId, {
$push: {
items: taskId
}
}, (err, list) => {
...
});
We get the latest list with list
.
$push
appends an item to the items
list in the document.
Conclusion
We can get the latest list after the update.
We can stub dependencies with rewire
.
We can use HTML templates with Nodemailer.
Mongoose methods return promises.