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.
Custom Validation Using 2 Fields with Mongoose
To do custom validation using 2 fields with Mongoose, we can create a custom schema and a validation function and pass that as the value of a field in the object we pass into the Schema
constructor.
For instance, we can write:
const dateRangeSchema = {
startDate: { type: Date },
endDate: { type: Date }
};
const checkDates = (value) => {
return value.endDate < value.startDate;
}
const schema = new Schema({
dateRange: { type: dateRangeSchema, validate: checkDates }
});
We created the dateRangeSchema
with the startDate
and endDate
fields.
Also, we created thew checkDates
function to return the date range.
And then we pass both into the object to specify the data type for a field.
We can also pass in a callback to validate
by writing:
schema.pre('validate', function(next) {
if (this.startDate > this.endDate) {
next(new Error('start date is after the end date'));
} else {
next();
}
});
We get the startDate
and endDate
values from the model and call next
with an error if the start date is bigger than the end date.
Otherwise, we call next
with nothing to proceed as normal.
Format a Date Coming from MongoDB
We can format a date coming from MongoDB with the toDateString
method.
For instance, we can write:
Schema
.virtual('date')
.get(function() {
return this._id.generationTime.toDateString();
});
We can also use the moment.js library to make our lives easier.
For instance, we can write:
Schema
.virtual('date')
.get(function() {
return moment(this._id.generationTime).format("YYYY-MM-DD HH:mm");
});
We called the format
method to format the moment object created from the moment
function into the date format we want.
It’s returned as a string.
Variable in Class Name in Jade/Pug Template
We can interpolate a string into a Jade/Pug template by writing:
div(class="language-#{session.language}")
Listen to All Interfaces Instead of Localhost Only in an Express App
We listen to all interfaces in an Express app by passing in '0.0.0.0'
as the 2nd argument of listen
.
For instance, we can write:
const express = require('express');
const app = express();
app.listen(3000, '0.0.0.0');
Accessing EJS Variable in Javascript Logic
If we have a route that renders an EJS template, we can render the variable that’s passed in from the render
method.
For instance, we can write:
app.get("/post/:title, (req, res) => {
//...
res.render("post", { title, description });
}
to create our route,
Then in our EJS template, we can write:
<% if (title) { %>
<h2>Post</h2>
<script>
const postTitle = <%= title %>
</script>
<% } %>
We get the title
from the object in the 2nd argument.
Then we interpolate the title
into the template.
Now we can assign that to a variable.
End an Express.js POST Response
We call res.end
to end the response to end the response.
For instance, we can write:
res.end('hello');
Or we can render a template and then call res.end
:
res.render('some.template');
res.end();
Shut Down an Express Server Gracefully When Its Process Is Killed
We can listen to the SIGTERM
and SIGINT
signals and then run our code in the handler for those signals and close the server in the callback.
For instance, we can write:
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('hello'});
const server = app.listen(3000);
setInterval(() => server.getConnections((err, connections) => {
console.log(`${connections} connections currently open`)
}), 1000);
process.on('SIGTERM', shutDown);
process.on('SIGINT', shutDown);
let connections = [];
server.on('connection', connection => {
connections.push(connection);
connection.on('close', () => {
connections = connections.filter(curr => curr !== connection)
});
});
const shutDown = () => {
server.close(() => {
process.exit(0);
});
setTimeout(() => {
process.exit(1);
}, 10000);
connections.forEach(curr => curr.end());
setTimeout(() => connections.forEach(curr => curr.destroy()), 5000);
}
We listen to the SIGTERM
and SIGINT
signals with the process.on
method.
We pass in the shutDown
function, where we call server.close
to close the connections.
We also exit with code 1 after 10 seconds if the connections aren’t closed successfully.
The connections are stored in the connections
array and call end
to close each connection.
We also call destroy
to destroy the connections after 5 seconds.
The connections cames from the connection
event handler where we pushed new connection objects into the connections
array.
We also add the close
handler with the filter
method.
Conclusion
We can validate multiple fields concurrently with Mongoose.
Also, we can shut down connections gracefully.
We can also format the date coming from MongoDB.