Difference between async(req,res,next) and async(req,res,()=>{} - javascript

I recently came across this code and I fail to understand why the next has been omitted from the protect function(inside protectandauth function) while it is included in the protect function originally.
I want to know the difference between protect=async(req,res,next)and protect=async(req,res,()=>{}.
I also see that even though next is omitted in the protect(the one inside protectandauth) function, it is still used in the code after the 'if' statement, how is that possible?
Code:
export const protect = async (req, res, next) => {
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
let token;
token = req.headers.authorization.split(" ")[1];
const decoded = jwt.verify(token, "kris");
req.userId = decoded.id;
try {
req.user = await User.findById(req.userId).select("-password");
next();
} catch (error) {
res.status(401).json(error.message);
}
if (!token) {
res.status(404).json("no token found");
}
}
};
export const protectandauth = async (req, res, next) => {
protect(req, res, () => {
if (req.userId == req.params.id) {
next();
} else {
res.status(401).json("not authorised");
}
});
};

Every callback where you access req and res, you can also access next. next is a function that's used to to say "pass to the next callback", knowing that a request can be processed by multiple callbacks, like so:
const firstCallback= (req, res, next) => {}
const secondCallback= (req, res, next) => {}
app.get("/", firstCallback);
app.get("/", secondCallback);
// or using this syntax
app.get("/", firstCallback, secondCallback);
In the above example, when a request comes to /, it's handled first by firstCallback, and it's one of the two below scenarios (otherwise the request will hang, and the user won't get a response):
It stops the request by calling one of the res methods, like res.status(401).json("not authorised");
It says "pass to the next callback" calling next(), and then secondCallback handles it.
If next is omitted from the parameters, you will be calling next() where it's undefined, and that throws an error. Speaking of the use of protect function, if you notice, there is next as part of protectandauth's parameters, and it's that next that's used inside protect's third parameter, which is:
() => {
if (req.userId == req.params.id) {
next();
} else {
res.status(401).json("not authorised");
}
}
And in this specific code you have, the above function is passed as next in protect's definition.

We use next if we want to pass our request to the next middleware in line. Maybe in protect, the programmer might not want to pass the req to the next middleware but in protectandauth he want to pass the req to the next middleware if this condition turns out to be true
if (req.userId == req.params.id) {
next();
}

Related

Why does callback function work when there are fewer arguments?

Code
Can someone please explain why this code works when in the function verifyUser, the function verifyToken is passed a callback function as the fourth argument. But if we look at the verifyToken function, it only has 3 parameters/arguments. How does this work????
import jwt from "jsonwebtoken";
import { createError } from "../utils/error.js";
export const verifyToken = (req, res, next) => {
const token = req.cookies.access_token;
if (!token) {
return next(createError(401, "You are not authenticated!"));
}
//Verifying if token is correct
//Error (err) or token data (user) are returned by verify function
jwt.verify(token, process.env.JWT, (err, user) => {
if (err) return next(createError(403, "Token is not valid!"));
req.user = user;
next();
});
};
export const verifyUser = (req, res, next) => {
verifyToken(req, res, next, () => {
if (req.user.id === req.params.id || req.user.isAdmin) {
next();
} else {
return next(createError(403, "You are not authorized!"));
}
});
};
I went digging in Express's source code and found this documentation
Once the next() function is invoked, just like middleware
it will continue on to execute the route, or subsequent parameter functions.
Source
So it looks like next() first tries to call a callback argument if it it's passed, then tries to call the next middleware.
I think the reason they did this, is to hardcode or chain a call to verifyToken before verifyUser without changing their implementation of next() which would jump to the next middleware when called in verifyToken instead of continuing verifyUser.
I wrote an example script that uses the same idea here:
function printResult(object, next) {
console.log("The final results is: " + object.result);
next();
}
function printLog(object, next){
console.log('Running printLog')
console.log('The current result is: ' + object.result)
next();
}
function add5(object, next) {
// Chain printLog before add5 so that it always runs before it
printLog(object, next, () => {
console.log('Now running add5')
object.result = object.result + 5;
next();
})
}
function addOne(object, next) {
console.log('Running addOne')
object.result = object.result + 1;
next();
}
function callStack(stack, object) {
function next(index, object) {
return function runNext() {
let caller = runNext.caller
if(caller.name !== '' && caller.arguments[2]) {
caller.arguments[2]()
} else if (stack[index + 1]){
stack[index + 1](object, next(index + 1, object));
}
}
}
stack[0](object, next(0, object));
}
const stack = [addOne, add5, printResult]
const object = {result: 0}
callStack(stack, object)
Note that the anonymous function check caller.name !== '' is there because checking the arguments property of an anonymous function throws an error.
More thorough explanation of why this is important.
So if you're app is like this there's no problem:
Middleware 1
next() goes to next middleware
verifyToken (Middleware 2)
next() goes to next middleware
Middleware 3
But if it was like this and next() didn't call the parameter function:
Middleware 1
next() goes to next middleware
verifyUser (Middleware 2)
calls verifyToken
next() in verifyToken goes to next middleware <- This is an issue
Continue verifyUser <- Because this never happens
next() goes to next middleware
Middleware 3
So they let next() call a parameter function:
Middleware 1
next() goes to next middleware
verifyUser (Middleware 2)
calls verifyToken with verifyUser's implementation as a callback veryifyCB (jus an alias for th example)
next() in verifyToken checks for a callback, finds verifyCB and calls it
next() in verifyCB goes to next middleware
Middleware 3

javascript:how does it work when a function returns another function and accepts another function as parameters

I followed the youtube Node & Express project tutorial and Im confused facing these code:
This is in async js file:
const asyncHWrapper = (fn) => {
return async (req, res, next) => {
try {
await fn(req, res, next);
} catch (error) {
next(error);
}
};
};
module.exports = asyncHWrapper;
And this is the usage:
const Task = require("../models/taskModel");
const asyncWrapper = require("../middleware/async");
const { createCustomError } = require("../errors/customErrors");
const getAllTasks = asyncWrapper(async (req, res) => {
const tasks = await Task.find({});
res.status(200).json({ tasks });
});
Im just confused about these questions:
Does is necessary to return an arrow function in the asyncWrapper? Why doesn't just call the function?
Where do the params (req,res) in the asyncWrapper function come from? In the "fn" function declaration?
Why should I write two pairs of async and await in the wrapper and when I call it?
Thanks a lot!
The youtube tutorial link :Node.js / Express Course - Build 4 Projects
Let me analyze the code first, and then I'll answer your question.
So here is your wrapper
const asyncHWrapper = (fn) => {
return async (req, res, next) => {
try {
await fn(req, res, next);
} catch (error) {
next(error);
}
};
};
and here is how it is used
const getAllTasks = asyncWrapper(async (req, res) => {
const tasks = await Task.find({});
res.status(200).json({ tasks });
});
the asyncWrapper accept an fn param, in this case, it is this function:
async (req, res) => {
const tasks = await Task.find({});
res.status(200).json({ tasks });
}
after asyncHWrapper is called with the above function, it will return another function, in this case, the return function is assigned as the name getAllTasks.
Now for your question:
Does is necessary to return an arrow function in the asyncWrapper? Why doesn't just call the function?
Well basically you can write it like this
const asyncHWrapper = async (fn, req, res, next) => {
try {
await fn(req, res, next);
} catch (error) {
next(error);
}
};
And call it like this
await asyncHWrapper(async (req, res) => {
const tasks = await Task.find({});
res.status(200).json({ tasks });
}, req, res, next)
But in this case, it's just a normal function with callback, it's not a wrapper, and its name shouldn't be asyncHWrapper.
Where do the params (req,res) in the asyncWrapper function come from? In the "fn" function declaration?
No, it comes from getAllTasks, your fn is just consuming two values (req, res), and the next param will be used for error handling. So when you call getAllTask, you must pass in three params like this getAllTasks(req, res, next)
Why should I write two pairs of async and await in the wrapper and when I call it?
I'm not sure what you meant by "two pairs of async and await". I assume you're referring to await when calling getAllTasks and await when calling fn?
That's just because both of them are async functions.
I hope that this answer can help you think about the concept of a "wrapper". Let's say we have a function divide:
const divide = (a,b) => a/b;
You can use this in normal code quite easily:
x = divide(10,5); // sets x to 2.
But you may decide that you care about the possibility of errors. In this case, division by zero is a possibility. You could certainly include some error handling code where you define the divide function. But you could also choose to "wrap" divide with an error handler. This way, we can keep the error handling aspects away from the main division logic. We would like to be able to define a safeDivide function like this:
const safeDivide = catchErrors(divide);
In the same way that divide is a function that takes two arguments, safeDivide also has to be a function that takes two arguments. So the catchErrors wrapper will have to return a function. We will start with something like this:
const catchErrors = (fn) => {
return (p,q) => fn(p,q);
}
If you pass a function fn to catchErrors, it will return a function. That returned function takes two arguments p and q, and returns fn(p,q). So far, this doesn't really achieve anything (except limiting the number of arguments). But now, we can add a try/catch block. I'll do it in a couple of steps, because the notation can be confusing.
The first step is to put an explicit return inside the inner arrow function.
const catchErrors = (fn) => {
return (p,q) => {
return fn(p,q);
}
}
This is technically the same code - it just looks slightly different. Now we add the try/catch.
const catchErrors = (fn) => {
return (p,q) => {
try {
return fn(p,q);
} catch (e) {
console.log("Error occurred. Continuing with null result.");
return null;
}
}
}
So now, the function returned from catchErrors will do the same as the original function, except when an exception is thrown, in which case it will return null. (I'm not saying that this is the best general way to handle exceptions, but it's useful as an example, and it's related to the original question.)
So now look again at where we use this catchErrors wrapper function.
const safeDivide = catchErrors(divide);
When you call the wrapper catchErrors with function divide, it doesn't actually do any dividing - it doesn't yet have any numbers to divide. Instead, it builds up a new function that, whenever it is called, would do the dividing, and catch any exception that arises. I hope that answers your first question.
Your second question is where req and res come from. They are names given to arguments that will be passed to the function. They can be passed to the wrapped function (along with a 3rd argument next), and they will also be passed to the inner (nameless) function which includes calls to Task.find and res.status(200). Those arguments will be provided by the Express (or other) web framework.
I will leave your 3rd question, on the async/await aspects of the wrapper, for another answer.

How could I generalize a http response handler in Node.js?

I'm writing a rest api for a node application, and I find myself rewriting something like the following a lot:
function(req, res, next) {
databaseCall()
.then( (results) => {
if (results != null) {
res.status(200).send(results);
} else {
res.sendStatus(404);
}
})
.catch(function(err) {
console.log("Request error: " + err.stack);
res.sendStatus(500);
})
}
I would like to refactor the response portion, so I can do something like
databaseCall()
.then(handleResponse)
where handleResponse would take care of the whole response/catch process.
But I can't quite figure out how to do that. The databaseCall method varies depending on the endpoint - sometimes it takes a parameter, sometimes not. I could make a generic function expression that takes the databaseCall result and stick it in the promise chain, but I don't know how I could access the response object inside that function. I know I could add another function to combine everything, like so:
function(databaseCall, parameter, req, res, next) {
databaseCall(parameter)
.then( (results) => {
if (results != null) {
res.status(200).send(results);
} else {
res.sendStatus(404);
}
})
.catch( (err) => {
console.log("Request error: " + err.stack);
res.sendStatus(500);
})
}
But that seems ugly since databaseCall could have 0-several parameters. I'd think there's a more elegant solution.
You're probably thinking in the right direction, you just need to take it a step further and keep the db call outside the generic handler, and pass it as a promise instead
// generic handler for db promise
// the promise is created outside and passed as arg
function responseFromDb(databaseCallPromise, res) {
databaseCallPromise
.then((results) => {
if (results != null) {
res.status(200).send(results);
} else {
res.sendStatus(404);
}
})
.catch((err) => {
console.log(`Request error: ${err.stack}`);
res.sendStatus(500);
});
}
// handler per request, only needs to create db call with the desired params
// and pass it to the generic handler, which will take care of sending the response
function(req, res, next) {
responseFromDb(databaseCall(param1, param2), res)
}

ExpressJS: Promises and Error Handling middleware

I have some error handling middleware defined and a route returning a promise. But when that promise gives an error, I have to manually append .catch(err => next(err)) after every promise. While its not a problem, isn't it sensible for ExpressJs to see if a route returns a promise and if so call the error handling middleware automatically.
My current shortened code:
// errorHandlers.js
function sequelizeValidationError (err, req, res, next) {
if (err.name && err.name == 'SequelizeValidationError')
res.status(400).send(err.errors)
else next(err)
}
// auth.js
router.post ('/register', middleware.isNotAuthenticated, (req, res, next) => {
const { email, password, name } = req.body;
return models.User.find({where : { email }}).then(user => {
if (user) {
if (user.password == password) sendToken(user.id, res);
else res.sendStatus(401);
} else {
return models.User.create({
email, password, name
}).then(user => {
sendToken(user.id, res);
})
}
}).catch(next)
})
// index.js
router.use('/auth', require('./auth'))
router.use(errorHandlers.sequelizeValidationError)
For example, currently I could have forgot to write catch at one place and the server would have failed.
Am I missing out on something? How can I avoid having to type the catch every time?
This is already filed.
I had filed a duplicate bug
As of now the best bet seems to be to use a wrap function .
Also see #robertklep 's comment above. promise-express-router may be useful if you donot use route-params . express-co seems to be a wrap function + more generator-based goodness

Restify: "override" default next

I want to kinda override default next in Restify. E.g. now i have code like
server.post('/names', function (req, res, next) {
names = req.params.names;
if (!Array.isArray(names)) {
return next(new restify.errors.BadRequestError('names field is wrong or missing'));
}
res.send({ code: "OK" });
return next();
});
I want it to be just
server.post('/names', function (req, res, next) {
names = req.params.names;
if (!Array.isArray(names)) {
return next(new restify.errors.BadRequestError('names field is wrong or missing'));
}
// Add names to DB
return next();
});
Where next (for non-error results) is like
function next(res) {
if (!body.hasOwnProperty("code")) {
body["code"] = "OK";
}
res.send(body);
}
What is the best way to implement this?
I think you may be looking for a handler that executes after all other handlers in the chain are done. Consider the "after" event handler. In the documentation they show an example for audit logging.
You should be able to use that same thing to update the response body as needed. The code might look something like this...
server.on('after', function (request, response, route, error) {});
Keep in mind, this still requires you to return next(); from all of the other handlers in the chain.

Categories