Where does next() go in Express js? - javascript

I'm new to javascript, nodejs, and express, and confused of using next().
I want my code to move on to the next router with next(), but it seems to move on to the next then.
My code:
//validation
router.post('/requests', (req, res, next) => {
let {myData} = req.body
basicCheck(res, cluster, myData)
.then(() => {
if (myCheck()) {
next()
return // Doesn't need to do rest of the code. Just move on to the next router.post
}
...
return Promise.all(somePromises)
})
.then(() => {
...
return Promise.all(somePromises)
})
.then(() => {
if (someCheck() {
next()
} else {
res.status(400).send('message') // My code reaches here! even when myCheck() is true
}
})
.catch((err) => {
...
})
})
// where next() needs to be
router.post('/requests', (req, res) => {
...
})
When next() is outside the basicCheck, next() goes to the next router.post.
I don't get the concept of where next() indicates.
How can I correct this code while doing myCheck() inside basicCheck()?

With next() you move to the next middleware.
Exapmle:
You have a route like:
app.get("/", (req, res, next) => {
res.send("hello")
})
Instead of using an anonymous function you can declare an function and use it it like:
function firstMiddleware(req, res, next){
res.send("hello")
}
app.get("/", firstMiddleware);
What you can do is you can have multiple middlewares in your route like:
function firstMiddleware(req, res, next){
console.log("hy");
next()
}
function secondMiddleware(req,res,next) {
console.log("hello")
res.send("hello");
}
app.get("/", firstMiddleware, secondMiddleware);
As you can see. In my first middleware i use next(). This tells express.js to move to the next middleware in this case secondMiddleware
The middlewares gets executed from the left to right and with next() you tell them to move to the next until you are on the end.
Usually the last middleware is your API endpoint and you should not use next() otherwise you would "jump out" of your route and you would receive an error if you have defined an global error handler
Also sidenote: A bonus would be to seperate your routes and logic by creating an file called controller.js for example.
controller.js
function firstMiddleware(req, res, next){
console.log("hy");
next()
}
function secondMiddleware(req,res,next) {
console.log("hello")
res.send("hello");
}
module.exports = {
firstMiddleware,
secondMiddleware
}
Now you can import it:
const { firstMiddleware, secondMiddleware } = require("./controller.js");
app.get("/", firstMiddleware, secondMiddleware);
This makes your code easier to maintain as it grows
EDIT:
router.post("/requests", async (req, res, next) => {
let { myData } = req.body;
let checkresult = await awbasicCheck(res, cluster, myData);
if (myCheck()) {
return next();
}
let someResults = await Promise.all(somePromises);
let someMoreResults = await Promise.all(somePromises);
if (someCheck()) {
return next();
} else {
res.status(400).send("message"); // My code reaches here! even when myCheck() is true
}
});
You use return witch yes stops the function from execution BUT what you also do is an promise chaining.
I have written here an async / await approach

Related

How to use next() function in Next JS API like Express JS?

While making an API in Next JS, where I pass three parameter to my API function (req, res, next) here is the code :
import catchAsyncErrors from "../../../middleware/catchAsyncErrors.js";
import connectToMongo from "../../../middleware/db.js";
import isAuthenticatedUser from "../../../middleware/isAuthenticated";
import ErrorHandler from "../../../utils/errorHandler";
const handler = catchAsyncErrors(async (req, res, next) => {
try {
console.log(next); // Undefined
if (req.method === "POST") {
return next(new ErrorHandler("Not Allowed", 405));
// ^ Error
} else {
return res.status(500).send("INVALID REQUEST");
}
} catch (error) {
console.log(error);
}
});
export default connectToMongo(isAuthenticatedUser(handler));
I assure that ErrorHandler is working fine, but when I call this API it gives me the following Error:
TypeError: next is not a function
at eval (webpack-internal:///(api)/./pages/api/auth/test.js:19:20)
at eval (webpack-internal:///(api)/./middleware/catchAsyncErrors.js:3:25)
at eval (webpack-internal:///(api)/./middleware/isAuthenticated.js:22:16)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
In Express JS we pass next parameter to call next function or error handler but it seems like it doesn't work with Next JS. I am new in this framework so I need your help in this.
So I found that we cannot use next() function in next JS like we used to do in express JS. Next JS API function accept only two parameters (req, res).
To use next() function to call other middleware, check out the bellow example :
import middleware1 from './middleware/func1';
import middleware2 from './middleware/func2';
const handler = async(req, res)=>{
//Your Code here
}
export default middleware1(middleware2(handler));
In the middleware functions:
middleware 1 :
const middleware1 = (handler) => {
return (req, res) =>{
//middleware function here
return handler(req, res)
}
}
export default middleware1;
middleware 2 :
const middleware2 = (handler) => {
return (req, res) =>{
//middleware function here
return handler(req, res)
}
}
export default middleware2;
As you can see both middleware take handler in parameter and return handler at end of code.
Make sure to return handler(req, res) at the end of the function as given in code

How to create a reusable code for passport.authenticate?

I have multiple controllers and each controller has multiple methods. In each method I authenticate the user and use the user id returned from the authentication to get the data from database. I am trying to create reusable code for authentication since the code is repeated.
In the controller:
const authenticate = require('../utils/user-authenticate');
exports.getData = async (req, res, next) => {
const userId = await authenticate.user(req, res, next);
console.log(userId);
};
And in the authentication I have:
exports.user = (req, res, next) => passport.authenticate('jwt', async (error, result) => {
if (error) {
// Send response using res.status(401);
} else {
return result;
}
})(req, res, next);
The console.log(userId); prints undefined always. This is print before passport finishes. Looks like async/await does not work the way I want here.
It works if I use await authenticate.user(req, res, next).then() but isn't it possible to assign the result directly to userId variable?
If I use return next('1'): first time undefined but second time it prints 1.
wrapped into a promise:
exports.user = (req, res, next) => new Promise((resolve, reject) => {
passport.authenticate('jwt', async (error, result) => {
if (error) {
// reject(error)
// Send response using res.status(401);
} else {
resolve(result);
}
})(req, res, next);
})
but think about:
//app.use or something similar
addMiddleware(authJWT);
// later in the chain
useMiddleware((req, res, next)=>{
// test auth or end chain
if(!req.JWT_user) return;
req.customField = 'one for the chain'
// process next middleware
next()
});
Thanks #Estradiaz for the suggestion:
exports.user returns undefined ... Return is scoped within inner
callback - if you want to pass it outside wrap it into a promise
Reusable passport.authenticate:
exports.user = (req, res) => {
return new Promise(resolve => {
passport.authenticate('jwt', null, async (error, result) => {
if (error) {
email.sendError(res, error, null);
} else if (result) {
resolve(result);
} else {
return res.status(401).json({errors: responses['1']});
}
})(req, res);
});
};
And this is how I use it in my controller, for instance in a function:
exports.getData = async (req, res, next) => {
const userId = await authenticate.user(req, res);
};

Get the session on the two routers

I have 2 routers
router1
app.post ('/ consultations', function (req, res) {
req.session.nombre = 'administrator';
console.log ('test', req.session.name); // there the session is saved well
});
router2
router.get ('/', function (req, res) {
console.log ('retrieve session', req.session); // exit undefined
}
How can I get the session on the two routers?
EDIT:
i created a middleware
function mymiddleware(req,res,next){
req.session.nombre='MiNOMBRE';
}
and I try to get the middleware;
app.get('/miroute1',mymiddleware,(req,res) => {
console.log(req.session.nombre);//
but never enters
}
app.get('/miroute2',mymiddleware,(req,res) => {
console.log(req.session.nombre);//
but never enters
}
function mymiddleware(req,res,next){
req.session.nombre='MiNOMBRE';
next();
}
next() will call next middleware in sequence, which in your case is
(req,res) => {
console.log(req.session.nombre);}
I think in your middleware you have to call next()

Checking whether user is logged in passport.js

I use passport.js to authenticate user. I have 2 function there to check whether user is logged in or not.
First function:
isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
else {
res.redirect('/');
}
}
2nd function:
isLoggedInCheck(req, res) {
if (req.isAuthenticated()) {
return true;
}
else {
return false;
}
}
I take these 2 functions in class called Helper.
When I use the 1st function (I pass it in routes function as middleware) it works:
var Helper = require('../helpers/helper');
var helper = new Helper();
router.get('/', helper.isLoggedIn, admin.melihat_daftar_venue);
But when i want to use second function:
if (helper.isLoggedInCheck) {
//code
}
else{
}
The function just return function definition instead of true/false. How to fix it. Thanks
You are using isLoggedIn as a ExpressJS middleware while isLoggedInCheck inside condition that's why you need to call function( helper.isLoggedInCheck(req, res) inside if condition while define inside get function
if (helper.isLoggedInCheck(req, res)) {
//code
}
else{
}
and first one is
router.get('/', helper.isLoggedIn, admin.melihat_daftar_venue);
or (not recommended, just showing example)
router.get('/', (req, res, next) => {
helper.isLoggedIn(req, res, next)
}, admin.melihat_daftar_venue);

Node.js Restify code is executed after returning error

I have a router handler configured in a Restify route. In that handler I make a call to a custom module where I do some error checking. When I hit an error condition, I my code returns next(err). I see the error message in the browser, but for some reason my code continues executing after that as well.
The Restify router handler
HttpHandlers.prototype.callHttp = function(req, res, next) {
myUtils.checkInputRules(req, res, next, handlerConfig.inputRules);
//This code is getting executed:
logger.debug("Updated ...
The function being called:
myUtils.checkInputRules = function checkInputRule(req, res, next, inputRules) {
...
} else {
if (inputRule.ifFalse) {
var evalStr = inputRule.ifFalse;
if (evalStr != null) {
logger.debug("Executing condition.iFalse: "+evalStr);
//The code is itting this location
return next(new Error("Internal Error: Failure."));
...
You didn't include the entire code but the issue may be something like this: When you return from a function, it is important which function you return from. For example:
function handler(req, res, next) {
helper(req, res, next);
// this will still run
}
function helper(req, res, next) {
if (something) return next();
}
Here it seems that you are running the myUtils.checkInputRules function and you are returning from your myUtils.checkInputRules function, but you are not actually returning from HttpHandlers.prototype.callHttp so everything after myUtils.checkInputRules(req, res, next, handlerConfig.inputRules); is still executed.
You didn't show the entire code but it seems all synchronous. In that case you can do something like this:
function handler(req, res, next) {
if (helper(req, res, next)) {
// next() was already called
} else {
// do something else - next() not called yet...
}
}
function helper(req, res, next) {
if (something) {
next();
// indicate that next() was already called:
return true;
}
// possibly do something else
}

Categories

Resources