I have a module that exports some express middleware that looks like this:
// my_middleware.js
module.exports = (someMiddleware) => {
function loadExternalData (val) { ... }
moreMiddleware.use(async function (req, res, next) {
const externalData = loadExternalData(req.headers['some-info'])
someMiddleware(externalData, req, res, next)
})
return myMiddleware
}
I'm trying to test the return value of loadExternalData and I'm not sure how to do it. I've tried this
it ('returns the expected response', function() {
const myMiddleware = require('my_middleware.js')
const someMiddleware = require('some_middleware.js')
const loadExternalData = sinon.spy(myMiddleware, 'loadExternalData')
myMiddleware(someMiddleware)
loadExternalData.should.have.returned('some data')
})
Which gives me the error TypeError: Attempted to wrap undefined property loadRegionInfos as function
What is the correct way to test this?
Related
const express = require("express");
const expressAsyncHandler = require("express-async-handler");
const app = express();
const f = async () => {
return false;
};
app.get(
"/",
expressAsyncHandler(async () => {
throw await f();
}),
() => {
console.log("the bug!");
}
);
app.use((err, req, res, next) => {
console.log("caught!", err);
});
app.listen(4000, () => console.log("listening on port 4000..."));
Expected output on the console:
"caught!".
output:
the bug!.
question: Why? Is it a bug in async-express-handler package or is it a normal JavaScript behaviour? what if I want to throw await something inside? how ?
Your problem is that you're throwing the value false. This doesn't fit into nodejs' callback conventions (and by extension, express error handling), which requires the err parameter to get a truthy value to be considered an error. A much simpler way to reproduce the issue:
app.get(
"/",
(req, res, next) => {
Promise.reject(false).catch(next);
// or even just:
next(false);
},
() => {
console.log("the bug!");
}
);
So just don't do that! Always throw an Error, not a string, not something else, and this principle also holds for promise rejections.
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
I am checking if a user is logged in a route called forum. I am importing it like this.
The file is routes/forum.js
const isloggedinimport = require('../index')
I have the function on index.js
const isloggedin = (req,res,next) => {
if(req.user) {
next()
}
else {
res.render('loginerror',)
}
}
I am exporting with
module.exports = isloggedin
When I try to run this
router.get('/', isloggedinimport.isloggedin, (req, res) => {
res.render('monitors/monitorhome')
});
module.exports = router
I get the error that Route.get() requires a callback function but got a [object Undefined]
The error is on this line
router.get('/', isloggedinimport.isloggedin, (req, res) => {
How do I fix this?
When exporting the function, try using the following code:
module.exports.isloggedin = isloggedin
This will set the property isloggedin to the function so that when you call isloggedinimport.isloggedin, it will access the function properly. Alternatively, you could use the following code to export your function:
module.exports = isloggedin
and then use this code to import the function:
const isloggedin = require('../index')
...
router.get('/', isloggedin, (req, res) => {
res.render('monitors/monitorhome')
});
Had the same problem and fixed it by adding brackets around the function you want to export:
module.exports = {isloggedin};
I have an app where I have public routes and authenticated routes. isAuthenticated were applied for example to a news controller.
globalRouter: function (app) {
app.use((req, res, next) => {
logger.log("Endpoint: ", req.originalUrl);
next();
});
const userRouter = require("./user/controller");
const globalRouter = require("./global/controller");
const newsRouter = require("./news/controller");
app.use("/user", userRouter);
app.use("/global", globalRouter);
app.use("/news", middleware.isAuthenticated(), newsRouter); // here
}
And here is the isAuthenticated code written in middleware.js file.
const security = require("../utils/security");
const service = require("../user/service");
exports.isAuthenticated = function (req, res, next) {
let authorization = req.headers.authorization;
let token = null;
if (authorization.startsWith("Bearer ")) {
token = authorization.substring(7, authorization.length);
if (token !== null) {
service.checkUserTokenMiddleware(token, security).then((response) => {
console.log("checkUserTokenMiddleware", response);
if (response) {
next();
}
});
}
}
};
The problem is that I'm getting this error below when I npm start the app
TypeError: Cannot read property 'headers' of undefined at Object.exports.isAuthenticated
What am I missing here?
why do I get such an error meanwhile in my other file using the same method like req.body.blabla or req.headers.blabla is fine?
Any help will be much appreciated.
Regards.
Simply remove the brackets after the function call:
app.use("/news", middleware.isAuthenticated, newsRouter);
You don't have to call the function in the callback to app.use, Express will itself pass in req,res,next to the auth function and call it.
It depends on how you import, middleware.js. Since you are exporting, isAuthenticated as function. This should be not called before passing to app.use.
Other things to be noticed, you never call the next function on error or else.
Please have a look in the below example.
// middleware.js
const security = require("../utils/security");
const service = require("../user/service");
exports.isAuthenticated = function (req, res, next) {
let authorization = req.headers.authorization;
let token = null;
if (authorization.startsWith("Bearer ")) {
token = authorization.substring(7, authorization.length);
if (token !== null) {
service
.checkUserTokenMiddleware(token, security)
.then((response) => {
if (response) {
next();
}
})
.catch((error) => next(error));
} else {
next("UNAUTHORIZED");
}
} else {
next("UNAUTHORIZED");
}
};
// app.js
const middleware = require("./middleware")
app.use((req, res, next) => {
logger.log("Endpoint: ", req.originalUrl);
next();
});
const userRouter = require("./user/controller");
const globalRouter = require("./global/controller");
const newsRouter = require("./news/controller");
app.use("/user", userRouter);
app.use("/global", globalRouter);
app.use("/news", middleware.isAuthenticated, newsRouter); // here
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!