Can't send params to a high order function in JS. The function it's not getting req and res args
// In router.js
const { getAll } = require('./controller')
router.get('/coordinadores', getAll()('mentor'))
// In controller.js
exports.getAll = (req, res) => {
return (role) => {
var filter = { role }
if (req.user.role == 'mentor') filter = { role, centro: { "$in": req.user.centro } }
Model.find(filter, '-password -role -__v -createdAt -updatedAt -centro').lean().exec()
.then(list => { res.status(200).json({ list }) })
.catch(err => { errorHandler(req, res, err) })
}
}
// Result
// TypeError: Cannot read property 'user' of undefined
Here
router.get('/coordinadores', getAll()('mentor'))
you're calling getAll without any arguments. To create a HoF you should create it like this
const getAll = role => (req, res) => {
// your code
}
and then
router.get('/coordinadores', getAll('mentor'))
this will call the getAll function with mentor and it will return a function reference that will be called with req and res by express
For an alternate, express way is to pass values through middleware like:
function setDefaultRole((req, res, next) => {
if (not some check here) {
// if check fails, setting default role
req.user.role = 'mentor'
}
// call the next middleware
next();
})
function getAll((req, res, next) => {
if (req.user.role == 'mentor') {
// continue logic
filter = ???
}
})
Related
I'm new with JS/NodeJs.
I managed to authenticate with Google Firebase
verifyFirebase.js:
function checkAuth(req, res, next) {
if (req.header('auth-token')) {
admin.auth().verifyIdToken(req.header('auth-token'))
.then((decodedToken) => {
//return uid
let uid = decodedToken.uid
next()
}).catch((err) => {
console.log(err);
res.status(403).send('Unauthorized')
});
} else {
res.status(403).send('Unauthorized')
}
}
module.exports.checkAuth = checkAuth;
and I'm using it on the another files as below;
routes.js
const verify_firebase = require('./verifyFirebase').checkAuth;
router.get('/', verify_firebase, (req,res) => {
res.json("verified");
})
The "/" route is protected with verify_firebase function coming from verifyFirebase.js.
How can I access uid variable from routes.js? Because I need to access this uid within secured route.
i think this might work
function checkAuth(req, res, next) {
if (req.header('auth-token')) {
admin.auth().verifyIdToken(req.header('auth-token'))
.then((decodedToken) => {
//return uid
let uid = decodedToken.uid
req.decoded = {
uid:uid
};
next()
}).catch((err) => {
console.log(err);
res.status(403).send('Unauthorized')
});
} else {
res.status(403).send('Unauthorized')
}
}
module.exports.checkAuth = checkAuth;
You could set the uid variable as req.uid and use it within your routes.js file, like this:
verifyFirebase.js
...
.then((decodedToken) => {
//return uid
req.uid = decodedToken.uid
next()
}).catch((err) => {
console.log(err);
...
routes.js
const verify_firebase = require('./verifyFirebase').checkAuth;
router.get('/', verify_firebase, (req,res) => {
console.log('my uid:', req.uid);
res.json("verified");
})
Please, keep in mind that if you're gonna use typescript, you'll also need to define the correct type for it.
I have 2 functions... 1st one in auth.js, which does this:
const adminCheck = (req, res) => {
console.log(“one”)
UtilRole.roleCheck(req, res, ‘ADMIN’, (response) => {
if(response) {
return true
} else {
return false
}
})
}
module.exports = {
adminCheck
}
basically checks if the user is an admin in my table. that works, but I am trying to retrieve the boolean in my function in my index.js function, which is below.
router.get(‘/viewRegistration’, auth.ensureAuthenticated, function(req, res, next) {
console.log("authcheck: " + auth.adminCheck())
const user = JSON.parse(req.session.passport.user)
var query = “SELECT * FROM tkwdottawa WHERE email = ‘” + user.emailAddress + “’”;
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return res.send(‘sorry, were unable to establish a connection to the database. Please try again later.’);
conn.query(query, function (err, rows) {
if (err) {
Response.writeHead(404);
}
res.render(‘viewRegistration’,{page_title:“viewRegistration”,data:rows, user});
return conn.close(function () {
console.log(‘closed /viewRegistration’);
});
});
});
})
where I am logging the value in the console.log right under where I initialize the function, it is returning undefined. how can I fix this?
You need to use Promise and wrap all callbacks to actually return a given result value from a function that uses a callback because usually a callback is called asynchronously and simply returning a value from it does not help to catch it in a calling function.
const adminCheck = (req, res) => {
console.log(“one”)
return new Promise(resolve, reject) => {
UtilRole.roleCheck(req, res, ‘ADMIN’, (response) => {
if(response) {
resolve(true)
} else {
resolve(false)
}
})
}
});
then you need to await a result calling this function using await keyword and marking a calling function as async:
router.get(‘/viewRegistration’, auth.ensureAuthenticated, async function(req, res, next) {
console.log("authcheck: " + await auth.adminCheck())
const user = JSON.parse(req.session.passport.user)
var query = “SELECT * FROM tkwdottawa WHERE email = ‘” + user.emailAddress + “’”;
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return res.send(‘sorry, were unable to establish a connection to the database. Please try again later.’);
conn.query(query, function (err, rows) {
if (err) {
Response.writeHead(404);
}
res.render(‘viewRegistration’,{page_title:“viewRegistration”,data:rows, user});
return conn.close(function () {
console.log(‘closed /viewRegistration’);
});
});
});
})
That's simple. You just forgot to return the inner function's return value
const adminCheck = (req, res) => {
console.log(“one”)
return UtilRole.roleCheck(req, res, ‘ADMIN’, (response) => {
if(response) {
return true
} else {
return false
}
})
}
module.exports = {
adminCheck
}
I have functions addVideosFromAuthor and schedule. I want schedule function will call addVideosFromAuthor and set the time to run. But when I call addVideosFromAuthor(), I got error TypeError: undefined is not iterable!. Look like the data can't be read in schedule function.
Is this code correct? Can you help me with this issue?
// #input array: [url, url2...]
export const addVideosFromAuthor = async (req, res) => {
try {
// processing...
} catch (error) {
console.log(error)
}
}
// #input object with array url: {command:'start', url: [url, url2...]}
export const schedule = (req, res) => {
const cmd = req.body.command
const task = cron.schedule('0 0 0 * * *', () => {
addVideosFromAuthor(req.body.url, res)
})
if (cmd === 'start') {
task.start()
} else if (cmd === 'stop') {
task.stop()
} else {
task.destroy()
}
}
Thank you
I am calling the function createOne inside createProfile and createOne does not appear to be executed. I am trying to create a user in database. The route is working as expected its just i am not able to call function within a function.
Please help!
exports.createOne = Model =>
catchAsync(async (req, res, next) => {
console.log("I am in createone")
const doc = await Model.create(req.body);
res.status(201).json({
status: 'success',
data: {
data: doc
}
});
});
exports.createProfile = (req,res) => {
console.log(req.query.segment);
if(req.query.segment == "Tour"){
let Segment = Tour;
console.log(factory);
factory.createOne(Tour);
}
}
Kindly find below results of console log the function doesn't fire off at all.
Tour
{ getOne: [Function], createOne: [Function] }
POST /api/v1/midasCommon/?segment=Tour - - ms - -
The thing is, based on the definition of catchAsync you gave,
const catchAsync = fn => {
return (req, res, next) => {
fn(req, res, next).catch(next);
};
};
you are returning a function with catchAsync that never gets called. What you do with factory.createOne(Tour); is just call catchAsync, but you need one more call.
You can either do factory.createOne(Tour)(); or change createOne to be:
exports.createOne = Model =>
catchAsync(async (req, res, next) => {
console.log("I am in createone")
const doc = await Model.create(req.body);
res.status(201).json({
status: 'success',
data: {
data: doc
}
});
})(); // <-- Notice the call
I'm doing tests for middleware function and get an error:
TypeError: *** is not a function
My test.js
describe('Login', () => {
it('it must check that function create the token', () => {
const req = {
body: { email: 'user#mail.com', password: '12345' }
}
const res = { locals: sinon.spy() }
return authMiddleware.login(req, res) // authMiddleware.test.js:41
.then(res => {
expect(res.locals.token).to.not.be.undefined;
})
.catch(err => console.log(err));
});
});
and middleware.js
module.exports = User => ({
login(req, res, next) {
if (!req.body.email || !req.body.password) return res.sendStatus(401);
return User.findOne({ email: req.body.email })
.then(user => {
if (!user) return res.sendStatus(401);
if (!user.isValidPassword(req.body.password)) return
res.sendStatus(401);
let payload = { id: user.id };
let token = jwt.encode(payload, config.auth.jwtSecret);
res.locals.token = token;
next();
})
.catch(next);
},
});
Error:
TypeError: authMiddleware.login is not a function
at Context.it (test/api/middleware/authMiddleware.test.js:41:35)
What am I doing wrong?
Your middleware.js file exports an arrow function that accepts the User parameter. The return value of this function is an object which has a login method with an express middleware signature.
You should invoke login middleware like this:
const { login: loginMiddleware } = require('./middleware')(req.body);
loginMiddleware(req, res, next);