The code below demonstrates trying to log req.hash_id from middleware. It's showing up for me as undefined. Is there anyway that I can get this to work? Or easily parse ":hash" out in regular .use middleware?
app.param("hash",function(req, res, next, id){
req.hash_id = id;
return next();
});
app.use(function(req, res, next){
console.log(req.hash_id);
return next();
});
I don't think you can use req.params inside a middleware function as it is bound to specific routes. You could use req.query though, but then you have to write your routes differently, e.g. /user?hash=12345abc. Not sure about passing the value from app.param to app.use.
If you have a specific structure for your routes, like /user/:hash you could simply write
// that part is fine
app.param('hash',function(req, res, next, id){
req.hash_id = id;
return next();
});
app.all('/user/:hash', function(req, res, next) { // app.all instead app.use
console.log(req.hash_id);
next(); // continue to sending an answer or some html
});
// GET /user/steve -> steve
Related
I want to create a middleware function in express.js. which can monitor every requests and responses. I created a middleware but it can only monitor the requests, not the responses.
function middlewareFunc (req,res,next) {
console.log(req.body , req.params , req.query);
next();
}
You should know that res in function(req, res, next) is a instance of class http.ServerResponse. So it can be listen on finish event, please see the link: https://nodejs.org/api/stream.html#stream_event_finish
app.use(function (req, res, next) {
function afterResponse() {
res.removeListener('finish', afterRequest);
res.removeListener('close', afterRequest);
// action after response
}
res.on('finish', afterResponse);
res.on('close', afterResponse);
// action before request
// eventually calling `next()`
});
app.use(app.router);
app.use() and middleware can be used for "before" and a combination of the close and finish events can be used for "after."
For that you can write two middlewares
1) Before all request endpoints.
//middleware
function middlewareFunEarlier(req,res,next) {
console.log(req.body , req.params , req.query);
next();
}
app.use(middlewareFunEarlier);
app.get('/', function(req, res, next){
//do something
res.end();
});
2) After all end points. And you must have to use next() in all endpoints
app.get('/', function(req, res, next){
//do something
next();
});
app.use(middlewareFunLater);
//middlware
function middlewareFunLater(req, res, next){
console.log(res);
res.end();
}
It can be work around with existing tools.
Ok, so first of all, the reason you are only seeing the requests is because of how middleware works. Everything gets run once in a certain order, and runs only once. When your middleware gets run it is most likely before the response has been created. In order to get the response you would have to make your code run when your controller goes to render or something like that.
Second of all, it seems like basic logging is all you need.(weather it be with a library or just console logging stuff.)
I have been experimenting with nested routes as they are convenient in passing on variables
router.post('/postlinkone', function(req, res, next){
//define few variables (x,y)
//render or redirect to close this route
router.post('/postlinktwo', function(req, res, next){
//use (x,y)
//render or redirect
}
}
The problem is that express is able to pass on the variables (x,y) during initialization to postlinktwo however these variables are not refreshed in next cycles. Is there a way to hard refresh them or is there a easier way to pass variables
Express has the philosophy of building on the req object.
Instead of nesting routes, have independent routes that modify req, altering stuff that you want.
router.get('/routeOne', function(req, res, next) {
// do something
req._data = {};
req._data.x = 'bla bla';
// call next to move to the next route middleware
next();
});
router.get('/routeOne', function(req, res, next) {
// check if the params are still there.
console.log(req._data);
});
I would like to use a middleware for checking users credentials only for some routes (those that start with /user/), but to my surprise server.use does not take a route as first argument and with restify-namespace server.use effect is still global.
Is there other way better than passing my auth middleware to all routes alongside the controller?
I think I'm going to just use server.use and inside the middleware make the following route check:
if (req.url.indexOf('/user/') !== 0) {
return next();
}
Unfortunately restify doesn't seem to be like express, which support the * operator. Hence, What I would suggest is grouping the routes that you desire together and apply a .use before them.
That is:
server.get('/test', function(req, res, next) {
// no magic here. server.use hasn't been called yet.
});
server.use(function(req, res, next) {
// do your magic here
if(some condition) {
// magic worked!
next(); // call to move on to the next middleware.
} else {
// crap magic failed return error perhaps?
next(new Error('some error')); // to let the error handler handle it.
}
});
server.get('/admin/', function(req, res, next) {
// magic has to be performed prior to getting here!
});
server.get('/admin/users', function(req, res, next) {
// magic has to be performed prior to getting here!
});
However, I would personally advocate the use of express, but choose whatever fits your need.
I need an equivalent of following express.js code in simple node.js that I can use in middleware. I need to place some checks depending on the url and want to do it in a custom middleware.
app.get "/api/users/:username", (req,res) ->
req.params.username
I have the following code so far,
app.use (req,res,next)->
if url.parse(req.url,true).pathname is '/api/users/:username' #this wont be true as in the link there will be a actual username not ":username"
#my custom check that I want to apply
A trick would be to use this:
app.all '/api/users/:username', (req, res, next) ->
// your custom code here
next();
// followed by any other routes with the same patterns
app.get '/api/users/:username', (req,res) ->
...
If you only want to match GET requests, use app.get instead of app.all.
Or, if you only want to use the middleware on certain specific routes, you can use this (in JS this time):
var mySpecialMiddleware = function(req, res, next) {
// your check
next();
};
app.get('/api/users/:username', mySpecialMiddleware, function(req, res) {
...
});
EDIT another solution:
var mySpecialRoute = new express.Route('', '/api/users/:username');
app.use(function(req, res, next) {
if (mySpecialRoute.match(req.path)) {
// request matches your special route pattern
}
next();
});
But I don't see how this beats using app.all() as 'middleware'.
You can use node-js url-pattern module.
Make pattern:
var pattern = new UrlPattern('/stack/post(/:postId)');
Match pattern against url path:
pattern.match('/stack/post/22'); //{postId:'22'}
pattern.match('/stack/post/abc'); //{postId:'abc'}
pattern.match('/stack/post'); //{}
pattern.match('/stack/stack'); //null
For more information, see: https://www.npmjs.com/package/url-pattern
Just use the request and response objects as you would in a route handler for middleware, except call next() if you actually want the request to continue in the middleware stack.
app.use(function(req, res, next) {
if (req.path === '/path') {
// pass the request to routes
return next();
}
// you can redirect the request
res.redirect('/other/page');
// or change the route handler
req.url = '/new/path';
req.originalUrl // this stays the same even if URL is changed
});
In using Express, I have a route like:
app.get('*', function (req, res, next) {
// no route is matched
// so call next() to pass to the static middleware
next();
});
There's another route that is something like app.get('/myroute', function(req, res, next)...
Can I pass information through to that route from the first one via next?
Thanks #amakhrov. I can use res.locals and store information.