I would like to validate params using these kind of middleware. The problem is that router.param is always applied before the first middleware router.all (I also tried with router.use, it doesn't work because the param is common to both middlewares). Is there a way to execute Middleware 1 before router.param ?
// Middleware 1
router.all('/:firstId/checklist/:**secondId**/*',
(req, res, next) => {
console.log('Request matched')
next()
},
param('**secondId**', "Error message 2")
.isMongoId(),
checkValidationErrors
)
router.param('**secondId**', callback)
However, Middleware 1 does not work as I expected. If the param is a valid MongoDB ObjectId, 'Request matched' is logged, the next middlewares are applied accordingly depending on the request. If it is not a valid id, 'Request matched' is NOT logged, the expected error is NOT sent in the response. I get this error instead from Mongoose which comes from router.param :
MongooseError [CastError]: Cast to ObjectId failed for value "xxx" at path "_id" for model "XXX"
I tried to comment router.param and it solved the problem. So it is certainly related to the order of execution.
Thank you very much for your help
Flip this (The reason is in your case express is only looking for :firstId/* in both cases because it does fit for both scenarios. if the first pattern/path matches with the input URI, it does not go look for your middleware 2.
// Middleware 1
router.all('/:firstId/*',
param('firstId', "Error message 1")
.isMongoId(),
checkValidationErrors
)
// Middleware 2
router.all('/:firstId/checklist/:secondId/*',
(req, res, next) => {
console.log('Request matched')
next()
},
param('secondId', "Error message 2")
.isMongoId(),
checkValidationErrors
)
To
// Middleware 2
router.all('/:firstId/checklist/:secondId/*',
(req, res, next) => {
console.log('Request matched')
next()
},
param('secondId', "Error message 2")
.isMongoId(),
checkValidationErrors
)
// Middleware 1
router.all('/:firstId/*',
param('firstId', "Error message 1")
.isMongoId(),
checkValidationErrors
)
I could not find a way to use a middleware with the same parameter as router.param and execute it before router.param, since router.param seems to be executed first systematically. But there is a workaround to be able to do this : regrouping middlewares which you want to execute before router.param in a separate file.
Instead of :
app.js (main app file) routing to originalRouter (original router file).
The control flow should be :
app.js (main app file) routing to beforeParamMiddlewwareRouter routing to originalRouter (original router file)
OR
In app.js :
app.use('/path', beforeParamMiddlewwareRouter, originalRouter)
Feel free to offer a better solution if you have one. I am open to suggestions.
Related
I'm using express to interact with discord's oauth2 api.
When I request a user oauth token the server responds with a url like:
http://localhost:3000/index#token_type=Bearer&access_token=tkn&expires_in=int
I'm trying to extract the parameters after the # as with discords api parameters start with # unlike others which start with a ?
Because it doesn't start with a question mark I am unable to use the req.params.x property.
I thought, "No big deal, ill just get the url and extract it myself" but every single url accessor in express removes string after #. This includes req.url and req.originalUrl which both return the file path.
So how can I get url parameters started by hashtags instead of question marks?
Or How can I get the full url with content after hashtags
I was able to solve this problem by setting a custom query parser. Code snippet below.
const app = express();
app.set('query parser', (query) => {
return query.split('&').map(item => {
const [key, value] = item.split('=');
return {
key,
value
}
});
});
app.get('/', (req, res) => {
console.log(req.originalUrl); // Full URL starting with file path
})
So I'm trying to make authorization for routes with JWT, it all worked if used on routes.
app.get('/user/list', jwtMiddleware, action);
And the jwtMiddleware content is (more or less):
var token = req.headers.authorization;
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, process.env.SECRET_TOKEN, function(err, decoded) {
if (err) {
return res.status(401).send({
success: false,
message: 'Sign in to continue.'
});
} else {
// if everything is good, save to request for use in other routes
next();
}
});
} else {
// if there is no token
// return an error
return res.status(401).send({
success: false,
message: 'Sign in to continue.'
});
}
it works, but I have these image files in uploads/ folder which accessible by /upload/image-1.jpg and I want to prevent direct access to /upload/image-1.jpg by using wildcard routes app.get('/upload*', jwtMiddleware, action);
then I try accessing random route with upload prefix like /upload/test, the jwt middleware works. But if I explicitly type /upload/image-1.jpg the browser just show the image, it's like the middleware or wildcard route (/upload*) is not accessed (the console.log inside middleware didn't even fired).
Previously I use restify and restify-jwt-middleware, it could handle this case flawlessly but in express I can't find out why it doesn't work. Maybe because restify-jwt-middleware automatically registers all routes into jwt validation whereas express need to declare each route with jwt middleware manually.
is there anything I miss in this case? thank you.
add/modify to another route like app.get('/upload/:image', jwtMiddleware, action)
this will check all the route you mentioned /upload/*
EDIT :
put the static files(eg.uploaded files somewhere like images/upload) and route them using the serveStaticFiles plugin restify and put jwt middleware to verify the user login status.
server.get(
'/uploads/*',
jwtMiddleware,
restify.plugins.serveStaticFiles('./images/upload')
);
In case anyone still confused, here's my answer in express which is similar approach to yathomasi's
// the fake route
app.get('uploads/:name', jwtMiddleware, (req, res, next) => {
if (fs.existsSync('./realpath/' + req.params.name)) {
res.sendFile('./realpath/' + req.params.name);
} else {
res.status(404).body({status : 'ERROR', message : 'File not found'});
}
});
this way, the uploads/somefile.jpg is treated as route url not file url and will be processed by jwtMiddleware
I have a delete route that has 2 middleware functions Authcontroller.protect and authcontroller.restrictTo("admin, "lead-guide")
router
.delete(
authController.protect,
authController.restrictTo("admin", "lead-guide"),
tourController.deleteTour
);
Within restrictTo I have a check to see if the user has the proper "role" to perform that task and if they don't, express is supposed ot send a 403. I'm seeing that express never actually sends the response. it enters the if statement(i see the console successfully printing fialure) and then it just skips sending the response.
exports.restrictTo = (...roles) => {
return (req, res, next) => {
console.log(req.user.role);
if (!roles.includes(req.user.role)) {
console.log("failure");
return res.status(403).json({
status: fail,
message: "you do not have permission to perform this action"
});
console.log(req, res);
}
next();
};
};
Put a try/catch in your inner function and see if there's an exception being thrown.
From looking at your code, if the fail variable (which you don't show a definition for) is not defined, then that would throw an exception and keep the res.json() from executing.
I want to use the request module in my express app, but I am not sure where the actual requests code goes.
Usage:
When a user loads a page, make a GET request and populate the page with data.
When a users clicks on a item from a table, make a GET request.
When a user fills out a form, POST.
I tried searching for answers but it seems to be implied that the developer knows where to place the code.
Example of a code snippet using request that I am unsure where to place in the express app:
var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Show the HTML for the Google homepage.
}
})
I am guessing that I should not place the code in the server.js file especially if I am going to be making many different calls, but that's what it looks like others are doing on StackOverflow.
Does the request belong in a model?
If you are doing this in response to a user interaction, like clicking on something you can just do it from the route handler. Below, I just return the results to the client, or I pass an error to the next handler in the chain.
var request = require('request');
var express = require('express');
var app = express();
app.get('/click', function(req, res, next){
request('http://www.google.com', function (error, response, body) {
if (error || response.statusCode != 200)
return next(err);
response.send(body) // return the html to the client
})
});
app.listen(3000);
In bigger apps you might move routes into separate modules.
Here i use those codes:
// Initial web request.
app.get('/hello', function(req, res) {
// Forward to an io route.
req.io.route('hello')
})
app.io.route('hello', function(req) {
//Here use emit
req.io.emit("world","world");
})
it report an error as follow:
TypeError: Object #<Object> has no method 'emit'
at Object.hello (/Users/wensonsmith/ProjectX/Server/app.js:44:12)
at Manager.io.route (/Users/wensonsmith/ProjectX/Server/node_modules/express.io/lib/index.coffee:65:29)
at Object.request.io.route (/Users/wensonsmith/ProjectX/Server/node_modules/express.io/lib/index.coffee:143:29)
at /Users/wensonsmith/ProjectX/Server/app.js:39:12
at callbacks (/Users/wensonsmith/ProjectX/Server/node_modules/express.io/node_modules/express/lib/router/index.js:160:37)
at param (/Users/wensonsmith/ProjectX/Server/node_modules/express.io/node_modules/express/lib/router/index.js:134:11)
at pass (/Users/wensonsmith/ProjectX/Server/node_modules/express.io/node_modules/express/lib/router/index.js:141:5)
at Router._dispatch (/Users/wensonsmith/ProjectX/Server/node_modules/express.io/node_modules/express/lib/router/index.js:169:5)
at Object.router (/Users/wensonsmith/ProjectX/Server/node_modules/express.io/node_modules/express/lib/router/index.js:32:10)
at next (/Users/wensonsmith/ProjectX/Server/node_modules/express.io/node_modules/connect/lib/proto.js:190:15)
req.io.respond is OK .
Broadcast is also have some problem.It can broadcast ,but it doesn't stop after broadcast.
it run for a long while ,then return nothing ,and no error messages.
My code is
// Initial web request.
app.get('/hello', function(req, res) {
// Forward to an io route.
req.io.route('hello')
})
// Forward io route to another io route.
app.io.route('hello', function(req) {
req.io.broadcast("world","world");
})
It doesn't look like the code you're posting is the actual code, judging by the stack trace.
But apart from that: as far as I understand express.io, when you're forwarding an HTTP request to an io route, the io route should always send back a response with respond; otherwise, the HTTP request will stall.
So try this:
app.get('/hello', function(req, res) {
req.io.route('hello');
});
app.io.route('hello', function(req) {
// broadcast first...
req.io.broadcast("world","world");
// ...then send back an empty response
req.io.respond();
});
Just to make sure: req.io.broadcast will not send the message back to the client that initiated the request. If you want that, use app.io.broadcast instead (see docs).
Its only 50% answered ;) ::
.respond takes your arguments "directly" to emit them,
e.g.:
req.io.respond({hello: 'world'})