How do I create a catchall async error handler in express? - javascript

I am using express.js and I am trying to create a catchall async error handler.
Say I have three routes which all may throw error,
const app = express()
app.get('/user', async function(req,res) {
const res = await getUsers()
})
app.get('/questions', async function(req,res) {
const res = await getQuestions()
})
app.get('/answers', async function(req,res) {
const res = await getAnswers()
})
in these three routes, all getXX function might throw error.
I want to have just one async handler for all routes. Something like this
app.use(asyncHandler)
so I don't have to try/catch every place that may throw error. Is there any solution for this?
Thanks in advance!

It's best practice to write async/await in try/catch block. because await only takes resolve output from promise if error throw from await function it handles by the catch block.
In catch block next(error) called which go throw all following middleware until it is not found error handling minddler.
const app = require("../../Reference/node-post-demo/app")
app.get('/user', async function (req, res, next) {
try {
const res = await getUsers();
return res.json(res);
} catch (error) {
next(error)
}
})
app.get('/questions', async function (req, res, next) {
try {
const res = await getQuestions()
return res.json(res);
} catch (error) {
next(error)
}
})
app.get('/answers', async function (req, res, next) {
try {
const res = await getAnswers()
return res.json(res);
} catch (error) {
next(error)
}
})
app.use(async (error, req, res) => {
//here, your error hendling code
})

Related

ExpressJS Route Async Middleware

I'm trying to use a middleware in Express but I can't get it to work I get infinite loading time when I make a request. I searched on stackoverflow but I couldn't find any examples that used an async await middleware stored in a separate file. Can someone point me in the right direction?
isAuthenticated.js
const Auth = require('../auth/auth')
const isAuthenticated = async () => {
return async (request, response, next) => {
const token = request.cookies.token;
try {
const JWTVerify = await Auth.verifyJWTToken(token);
next()
} catch (error) {
response.json({ status: "failed", message: "Authentication failed invalid token" });
response.end();
}
}
}
module.exports = isAuthenticated
Server.js
const isAuthenticated = require('./middleware/isAuthenticated')
app.post('/some-route', isAuthenticated, async (request, response) => {
});
You returning a function, and thus the middleware is not passing the request forward.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.
check ---> http://expressjs.com/en/guide/writing-middleware.html
const Auth = require('../auth/auth')
const isAuthenticated = async (request, response, next) => {
const token = request.cookies.token;
try {
const JWTVerify = await Auth.verifyJWTToken(token);
next()
} catch (error) {
response.json({ status: "failed", message: "Authentication failed invalid token" });
response.end();
}
}
module.exports = isAuthenticated
I think the issue is the definition of your middleware. You are wrapping it inside a function, but you are not calling it. If you pass it like that to express, express will try to call it but the outer function just returns the inner function. The inner function thus never gets called so next() never gets called.
const isAuthenticated = async (request, response, next) => {
const token = request.cookies.token;
try {
const JWTVerify = await Auth.verifyJWTToken(token);
next()
} catch (error) {
response.json({ status: "failed", message: "Authentication failed invalid token" });
response.end();
}
}

My variable is always undefined, function returning before awaiting the query

const express = require('express')
const usersJs = require('./endpoints/users')
var cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.post('/addUser', (req, res) => {
result = usersJs.doAddUser().then(result => console.log(result))
res.json(result)
})
This is my server which is doing the call of doAdduser() from another file as you see bellow...
let stuff_i_want
module.exports.doAddUser = () => {
return addUser(async function (result) {
stuff_i_want = result;
return stuff_i_want
});
}
addUser = async (callback) => {
const mysql = require('mysql')
const connection = mysql.createConnection({
host: "localhost",
port: "",
user: "",
password: "",
database: ""
})
connection.connect(async function (err) {
if (err) throw err;
connection.query("SELECT * FROM USERS", async function (err, result) {
if (err) throw err;
stuff_i_want = result
});
});
return callback(result)
}
but the problem that result is always undefined in when im trying to res.json() it to the client, or when im trying console.log(result), its happening before addUser() which will make it undefined, tried with delay, with async await, but still result undefined in client and server but in doAdduser i can see the result from the database
I wanna be honest with you, this code looks super messi. However i have an solution for you.
You try to get the result outside the promise chain, that dont work. I would use the modern way async / await
const express = require('express')
const { addUser } = require('./endpoints/users')
var cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.post('/addUser', async (req, res) => {
try {
let result = await addUser();
return res.status(200).json(result);
} catch (err) {
console.log(err);
return res.status(500).json({ message: "Something went wrong" })
}
})
Also wrap it with an try / catch
Next to your mysql connection:
const mysql = rquire("mysql");
module.exports.addUser = () => {
return new Promise((resolve, reject) => {
const connection = mysql.createConnection({
host: "localhost",
port: "",
user: "",
password: "",
database: ""
});
connection.connect(err => {
if (err) reject(err);
connection.query("SELECT * FROM USERS", (err, result) => {
if (err) return reject(err);
return resolve(result);
});
});
});
};
import it on the top not somehwere in the middle of the code this is just confusing.
export a named module called addUser witch is an function.
That function returns an promise.
Then reject on errors and resolve if you got an result from your DB.
The try / catch block will catch the error.
Also add an status code to your response. I am not sure here i might be wrong but no status code means your request was successful even if something went wrong on the serverside
Its also good to have an router folder where you add all your routes and import the route handlers in there that looks something like this then:
const { addUserHandler } = require("./user");
router.post("/addUser", addUserHandler)
So routes and the logic are seperated and it doesnt look messi

Route not executing after middleware

So I'm creating an authentication route but failing after executing the middleware.
verifyToken.js
module.exports = function (req, res, next) {
const token = req.get('auth-token')
if (!token) return res.status(401).send('Access Denied!')
try {
const verified = jwt.verify(token, process.env.TOKEN_SECRET)
req.user = verified
console.log(req.user) // successfully logging
next()
} catch (err) {
res.setHeader('Content-Type', 'application/json');
res.status(403).send('Invalid Token')
}
}
user.controller.js
exports.currentUser = verifyToken, async (req, res) => { // after verify token throwing an error 404
console.log('HIT') // not logging
// return res.send(req.user)
}
user.route.js
const { currentUser } = require('../controllers/users');
router
.route('/currentuser')
.post(currentUser)
I tried your code and I couldn't log 'HIT' as well. I suggest the following, split the exports # exports.currentUser into
var verifyToken = require('./verifyToken.js')
var response = async (req, res) => {
console.log('HIT') // not logging
// return res.send(req.user)
}
module.exports.currentUser = {verifyToken, response}
Then re-write route.js like this to get it to work.
const { currentUser } = require('./controller.js');
router.get('/currentUser', currentUser.verifyToken, currentUser.response)
To utilize next(), I had to use router.get('/get', middleware, callback). I changed the codes so that I could test it. You will need to edit the codes according to your context!

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);
};

Async Error handling Wrapper does not work

I am trying to write a wrapper for express callback function displayUsers() in this case, it would append error handling logic to avoid using try catch everywhere.
The main issue is that fn() actually executes before being invoked by router.get
I am not sure why as I am returning it within a function, not executing it.
///Userroute.js
var router = require('express').Router();
var userModel = require('../models/user');
var asyncErrorHandler = require('../helpers/asyncErrorHandler');
var viewsDir = '../views/';
// get users from model
var displayUsers = async function(req, res, next) {
var users = await userModel.getUsers();
console.log(users);
res.render(`${viewsDir}/users.hbs`, {users:users})
};
var safeDisplayUsersfn = asyncErrorHandler(displayUsers);
router.get('/', safeDisplayUsersfn);
//asyncErrorHandler.js
module.exports = function (fn) {
return async function(req, res) {
try{
await fn();
}catch(error){
console.log('Error happened' + error);
res.status(500).send('Unexpected Error');
}finally{
}
}
}
fn() was executing correctly, what needed to be done is to pass parameters to the executing function: fn(req,res,next); Like:
module.exports = function (fn) {
return async function(req, res, next) {
try{
await fn(req, res, next);
}catch(error){
console.log('Error happened' + error);
res.status(500).send('Unexpected Error');
}finally{
}
}
}

Categories

Resources