Express.js Routing and Middleware
The imported express library returns a function that, when invoked, creates the Express application object (app). This object configures the server and define its routes.
const express = require('express');
const app = express();
A middleware is an express function called during route requests, it has access to the request and response objects, its next() function passes control to the next stack/route handler.
//It can be included directly in the Route request
function steps(req, res, next){
console.log("first step")
next()
}
app.get("/first", ,(req, res)=>{
res.send("end stack") //first step, end stack
})
The express method app.use() mounts the middlewares on the route paths.
If no route is specified then it's applied to every route, their order depends on when were they declared.
//Aplied to all requests routes
app.use(steps)
app.get("/ruota", (req, res)=>{
console.log("This is the return") //first step, this is the return
res.send("how does a middleware work")
})
//This middleware will be ignored.
app.use("/ruota", (req, res, next)=>{
console.log("This is the second")
next()
})
A middleware can end a route path with res.send() and res.redirect().
//If > 5 res.send, if not it redirects
function check(req, res, next){
req.params.part.length > 5 ? next() : res.redirect("/means")
}
app.get("/take/:part", check, (req, res)=>{
res.send("The params is higher than 5")
})
Middlewares can update req.body and pass error parameters to the route handler.
We can module.export middlewares to use() in the router.
//middle.js
function mezzo(req, res, next){
console.log("middle function")
next()
}
module.exports = mezzo;
//server.js
let preso = require("./middle")
app.use( preso1 )
Independent routing with express.router()
The express.router() class create independent routing instances, which need to be mounted to a specific path using app.use(), effectively prefixing all routes defined within the router.
it inherits methods and properties from the express framework (like middlewares).
//Router stored in routes/router.js
const router = express.Router();
function solo(req, res, next){
console.log( "added middle on router" )
next()
}
//path /localhost3030/first/ahead
router1.get("/ahead", solo, (req, res)=>{
console.log( req.body )
res.send("sent")
})
module.exports = router1;
//All previously defined middlewares will be aplied to the mounted router.
app.use(express.json()) //Will parse the router req.body
let rotta = require("./routes/router")
app.use("/first", rotta)
We implement route chaining using the router.route() method.
//Same HTTP route but different methods verbs
app.route('/users')
.get((req, res) => {
console.log("We got the get way")
res.send("Io volevo il film")
})
.post((req, res) => {
res.send("Lo stanno facendo")
});
Password hashing with bycryptjs
The bcrypt module is a wrapper library for the C-based bcrypt password hashing algorithm. It provides a javascript API to hash passwords, due to the C compilation, extra dependencies may be required depending on the platform.
The npm i bcryptjs module is a pure JavaScript implementation of the bcrypt algorithm, it doesn't require external code and runs directly in Node.js.
Its getSalt(rounds) method generates a random string used for the hash() of the password.
//bcryptjs is less performant than bcrypt but they share functions
//Being a drop-in replacement it inherits all the previous methods
//A higher rounds value for a more complex but slower hash.
const bcryptjs = require('bcryptjs');
const bcrypt = require("bcrypt");
const sale = await bcryptjs.genSalt(10)
const cryptopass = await bcryptjs.hash(password, sale)
Bcryptjs provides synchronous versions of its promise-based methods, which block the execution of the program until they complete and return a value.
console.log( bcrypt.genSalt(10)) //Promise { <pending> }
console.log( bcryptjs.genSaltSync(10)) //$2a$...
console.log( await bcrypt.genSalt(10)) //$2a$...
The compare() method compares a plaintext and a hashed password, using its salt, to return a boolean value.
//Ther is also compareSync
const newtrue = await bcryptjs.compare( password, hashpassword ) //true/false
//The salt value is visible in the hashed password
$2b$10$q.KYbb.xmNQ0KEikk5EfWenciYtBMJBsfhmPqnf7HTWeTcHnDAI5q
$2b$ is the bcrypt algorithm identifier.
<cost> is the round count, represented as a base-10 integer.
<salt> is the salt value, represented as a base-64 encoded string.
<hash> is the hashed password, represented as a base-64 encoded string.
The getRounds() method extracts the number of rounds used in the salt process.
//the same async and sync methods as for the compare.
bcryptjs.getRounds("$2b$....")
We manage its error handling with a try/catch block:
//An 401 error for compare() returning false
//An 500 error for errors in the compare() methods (like invalid arg, etc)
router.post("/sign-in", async (req, res) => {
try{
const isValidPassword = await bcrypt.compare( password, hashpassword );
if (!isValidPassword) {
return res.status(401).json({
error: "Invalid Credential",
isAuthenticated: false}
);
}
}catch (error) {
console.error(error.message + " non validated");
res.status(500).send({error: error.message});
}
})
Last updated
Was this helpful?