Currently, I am using many routes in Express. Some of the routes can be quite lengthy. A common route look like the following:
router.get('/api/comments', function(req, res, next){
Comment.find({"user": req.payload._id}).exec(function(err,comments){
if(err){return next(err); }
res.json(comments);
})
}
This works fine. But I am calling routes multiple times and it can be quite lengthy. So I am trying to create a callback function which can be invoked by the various routes. E.g.
var testFunction = function(req, res, next){
Comment.find({"user": req.payload._id}).exec(function(err,comments){
if(err){return next(err); }
res.json(comments);
})
}
router.get('/api/comments', testFunction(req,res,next));
However, I will always get a "req is not defined" error on the last line. Just wondering what I am doing wrong here?
router takes a function as argument not the result of executing that function.
router.get('/api/comments', testFunction); will work.
Try doing router.get('/api/comments', testFunction); instead of router.get('/api/comments', function(req, res, next)
Related
I want to do some logging in the application. The flow I'm currently think is I pass a middleware function to my other middleware, then called the middleware function inside it.
I know it might be confusing, but this is the case I'm having now, I already have error logging middleware but want to invoke it later when on response finish
//middleware that called other middleware
module.exports = function(loggingMiddleware) {
return function (req, res, next) {
res.on("finish", () => {
loggingMiddleware(req, res, next) // will be called twice here
}
next() // to other middleware
}
}
My concern is, is it ok to call the next twice?
Can someone please explain what's happening here? I know these are middleware for express, I'm looking at the syntax.
I understand the es6 syntax for mustBeLoggedIn but I'm not sure what const forbidden = message => (req, res, next) => { is doing. Is message another parameter that comes before req, res, next? If so, why isn't it in the parenthesis? I originally thought this was just assigning another variable name to the function. So I could call it either forbidden() or message(), no? But looking at how it's being used it looks more like a parameter...
Another interesting thing I noticed is that the middleware forbidden is being invoked in the get request and mustBeLoggedIn is only being passed and not invoked. Why?
const mustBeLoggedIn = (req, res, next) => {
if (!req.user) {
return res.status(401).send('You must be logged in')
}
next()
}
const forbidden = message => (req, res, next) => {
res.status(403).send(message)
}
module.exports = require('express').Router()
.get('/', forbidden('only admins can list users'), (req, res, next) =>
User.findAll()
.then(users => res.json(users))
.catch(next))
.post('/', (req, res, next) =>
User.create(req.body)
.then(user => res.status(201).json(user))
.catch(next))
.get('/:id', mustBeLoggedIn, (req, res, next) =>
User.findById(req.params.id)
.then(user => res.json(user))
.catch(next))
I dislike this use of the ES6 syntax as it obscures the meaning of the code only in the interest of brevity. The best code is not always the shortest possible way to write it. Give people tools and they will sometimes use them inappropriately.
forbidden() is a function that takes one argument message that returns a middleware handler that uses that one argument. So, it's a way of making a customized middleware handler that has a parameter pre-built-in. When you call forbidden(msg), it returns a middleware handler function which you can then use as middleware.
The ES5 way of writing this (ignoring for a moment the difference in this which would be different, but is not used here) would look like this:
const forbidden = function(message) {
return function(req, res, next) {
res.status(403).send(message);
}
}
So, when you call forbidden(someMsg), you get back a function that can be used as middleware.
If so, why isn't it in the parenthesis?
With the ES6 arrow syntax, a single argument does not have to be in parentheses. Only multiple arguments require parentheses.
Another interesting thing I noticed is that the middleware forbidden is being invoked in the get request
This is because invoking it returns the actual middleware function so you have to execute to get the return value which is then passed as the middleware.
and mustBeLoggedIn is only being passed and not invoked. Why?
Because it's already a middleware function, so you just want to pass a reference to it, not invoke it yet.
FYI, this route:
.get('/', forbidden('only admins can list users'), (req, res, next) =>
User.findAll()
.then(users => res.json(users))
.catch(next))
does not make sense to me based on the code you've shown because forbidden() will return a middleware that will ALWAYS return a 403 response and will not allow the next handler to get called. This would only make sense to me if forbidden() had logic in it to check if the current user is actually an admin or not (which you don't show).
I'm using a function that someone else wrote for express and passport, which defines the middleware(?) as follows:
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()){
return next();
}
else{
req.flash('error', 'You need to be logged in to access this page');
res.redirect('/login');
}
}
This function is used in the router as follows:
app.get('/page', isLoggedIn, function(req, res){
// ...
});
What I don't understand is, shouldn't the function be called with parameters req and res? Maybe the callback next is not necessary since it's the next argument of app.get, but how does the function access req and res? I would expect it to be called as follows:
app.get('/page', isLoggedIn(req, res), function(req, res){
// ...
});
How does it work without specifying the arguments?
Thanks,
Any functions that you pass to app.get() or app.use() are automatically called with req, res, next passed to them. That is how app.get() and app.use() are implemented.
To help you understand, this example:
app.get('/page', function(req, res){
console.log(req.params.foo);
});
is functionally the same as this:
app.get('/page', myHandler);
function myHandler(req, res) {
console.log(req.params.foo);
});
You do not want to do something like this:
app.get('/page', isLoggedIn(req, res), function(req, res){
// ...
});
because here you're attempting to execute isLoggedIn(req, res) (when req and res are not yet defined) and then pass it's returned value to app.get(). That is not what you want at all. You need to pass a function reference to app.get() and it will supply the parameters when it calls the function. Any time you put () after a function in Javascript, that means you want to execute it NOW. But, if you just pass the function's name, then that is a function reference which can be stored and called later as desired.
This code example is analogous to this:
var result = isLoggedIn(req, res);
app.get('/page', result, function(req, res){
// ...
});
Besides the fact that this would cause an error because req and res are not defined at program start time when this would execute, hopefully you can see that you don't want to execute isLoggedIn() now. Instead, you just want to pass a function reference so Express can call it later.
In this code
app.get('/page', isLoggedIn, function(req, res){
// ...
});
The app.get method is being called with three arguments:
the route to the page: /page
the middleware function
the request handler function
Basically, this code is telling the express framework that when a GET request is received for the /page path, then it should call two functions: first, the middleware function and second the handler function.
The important thing to note here is that it is the framework doing the work. The framework is going to call the middleware function, then it's going to call the handler function.
What I don't understand is, shouldn't the function be called with parameters req and res?
It will be called with these arguments, somewhere inside the get function. Suppose this is the simplified get, implemented as
// a super simple get that will expect a function
// and call the function with two arguments
function get( f ) {
var res = 1, req = 1;
f( res, req );
}
There are multiple ways of passing a function to get. For example, you pass an anonymous function
get( function( res, req ) {
return res + req;
}
You can also pass a named function defined elsewhere
function isLoggedIn( res, req ) {
return res + req;
}
get( isLoggedIn );
This however, is not what you'd expect:
get( isLoggedIn( res, req ) );
The problem here is that
isLoggedIn( res, req )
is no longer a function declaration. It is an invocation and the result of this invocation depends on what res and req are. With some luck, the invocation can even yield a number value, which means that get is no longer invoked with function as an argument but with the result of function invocation.
In short, to pass a named function to another function, you don't specify its arguments. The supposed syntax that would allow this doesn't even make sense because it would be indistinguishable from a syntax of actual function invocation (i.e. the value of the call).
I'm using Node with Express.js to write a back-end for a project I'm working on.
next() functions are used in middleware to move to the next piece in the middleware chain, and finally onto the app.VERB() function. Where and how (further down the line) do I access this variable?
Example code:
app.use(function (req, res, next) {
User.findOne({
'email': emailValue
}, function (err, foundUser) {
if (err) return next(err);
// Else do something
}
});
});
What has access to the err value passed to next()?
When you pass an error parameter into next, Express invokes whatever error middleware handler you've installed. The error middleware function has four arguments, so you'd install your own handler as:
app.use(function(err, req, res, next) {
// handle the err from a previous middleware's next(err) call
});
You'd typically add this at the end of your middleware chain so that it handles all other middlewares' errors.
See here for the Express documentation on this.
I'm trying to set a global function that is called on every page load, regardless of its location in my website. As per Express's API, I've used
app.all("*", doSomething);
to call the function doSomething on every page load, but it doesn't completely work. The function fires on every page load, except for page loads of the base domain (e.g. http://domain.com/pageA will call the function, but http://domain.com won't). Does anyone know what I'm doing wrong?
Thanks!
I bet that you placed
app.get('/', fn)
above
app.all("*", doSomething);
Remember that Express will execute middleware functions in the order they are registered until something sends a response
I know that's an old one, but still maybe useful to someone.
I think the problem could be:
app.use(express.static(path.join(__dirname, 'public')));
var router = express.Router();
router.use(function (req, res, next) {
console.log("middleware");
next();
});
router.get('/', function(req, res) {
console.log('root');
});
router.get('/anything', function(req, res) {
console.log('any other path');
});
where is middleware invoked on any path, but /
It happens because express.static by default serves public/index.html on /
To solve it add parameter to the static middleware:
app.use(express.static(path.join(__dirname, 'public'), {
index: false
}));
If you want to run some code on every request, you don't need to use the router.
Simply place a middleware above the router, and it will be called on every request:
app.use(function(req, res, next){
//whatever you put here will be executed
//on each request
next(); // BE SURE TO CALL next() !!
});
Hope this helps
Where is app.all('*') in the chain? If its after all the other routes, it might not be invoked.
app.post("/something",function(req,res,next){ ...dothings.... res.send(200); });
app.all('*',function(req,res) { ...this NEVER gets called. No next and res already sent });
Unless it was your intention to have it be last, in which case you have to be sure to call next() in the preceeding routes. For example:
app.post("/something",function(req,res,next){ ...dothings.... next();});
app.all('*',function(req,res) { ...this gets called });
Also, what's in doSomething? Are you sure its not getting called?
I also had this problem and I discovered that the number of arguments your doSomething function have might be a factor.
function doSomething(req, res, next) {
console.log('this will work');
}
whereas:
function doSomething(req, res, next, myOwnArgument) {
console.log('this will never work');
}