There are many ways to mock requests using things like supertest and nock but what I'm looking to do is to be able to create fake request objects, as if the request was going to a different URL, that can be passed on to other processing functions.
app.get("/render", function(req, res) {
// how do I do this?
var fake = createFakeRequest("/bar/?baz=qux", req);
// I want doStuff to believe the request came to /bar/?baz=qux
doStuff(fake, function(err, result) {
res.send(result);
});
});
I'm aware I could modify all of he variables such as req.path, req.query, req.url but I'm worried I may miss something, and it seems like someone out there must have already solved this problem.
The reason I need this behavior is that for any given URL in my CMS, there can be multiple drafts. Each draft will have different content elements, but those individual content elements may have logic based on the URL or query parameters. So even though the request came in as /render/?draft=1&url=/foo/bar/, I want the content element processors to believe the request came in to /foo/bar/ and be oblivious to the version system which actually handled the initial HTTP request.
Not sure to understand but seems like url rewriting, so using a middleware could work
function urlRewrite(req, res, next){
req.url ="...";
next();
}
and so
app.use(urlRewrite);
Be sure to use it at the right place (depending on your server goal)
Cause we maybe need params before the rewrite... and if rewrite, you may need it after...
EDIT
In my framework:
server.before(extractPath);
server.before(urlParams);
server.before(pathParams);
server.get("/foo", route.foo);
So I could write
server.before(extractPath);
=> server.before( function(req, res, next){
urlRewrite(req, res, function(){
extractPath(req, res, next);
}
});
server.before(urlParams);
server.before(pathParams);
server.get("/foo", route.foo);
If urlRewrite depends on urlParams, I could write
server.before(extractPath);
server.before(urlParams);
=> server.before( function(req, res, next){
urlRewrite(req, res, function(){
extractPath(req, res, function(){
urlParams(req, res, next);
});
});
});
server.before(pathParams);
server.get("/foo", route.foo);
As I said, it depends on your framework
Related
First of all, i have searched the solution to this problem and i didn't found anything. Sorry if it's duplicated.
I have in my express+node.js app two endpoints like this:
// Gets a tweet by unique id
app.get('/tweets:id', function(req, res, next) {
// Response management
});
// Gets mentions of user unique id
app.get('/tweets/mentions', function(req, res, next) {
// Response management
});
The problem is that requesting a GET petition to "/tweets/mentions", is attended first by "/tweets/:id" and later by "/tweets/mentions", making a conflict.
I have tried to change the declaration order of the endpoints, but always the request is attended by both endpoints.
Also I have tried things like "/tweets::mentions", but I need to access the endpoint via "/tweets/mentions", and I suppose there is a possible way.
How can i resolve this conflict?
Thanks.
Are you using next() in one of the handlers?
next() passes control to the next matching route, so in your example, if one of them is called and inside it you call next(), the other one will be called.
I allways recommend to use 'Router' if you have more than one base path because it helps you to keep it organized.
You can resolve the conflict by checking the value of req.params.id in the "tweet by id" handler.
For routes with additional parameters is always recommended to not use the same base path of other routes.
Something like could work for you:
app.get('/tweets/users/:id', function(req, res, next) {
// Response management
});
// Gets mentions of user unique id
app.get('/tweets/mentions', function(req, res, next) {
// Response management
});
I've got a NodeJS + Express Server setup with a router that looks like this:
app.route('/clients/:clientId)
.get(users.ensureAuthenticated, clients.read)
.put(users.ensureAuthenticated, clients.hasAuthorization, clients.update)
.delete(users.ensureAuthenticated, clients.hasAuthorization, clients.delete);
app.param('clientId', clients.clientByID);
My Problem is that users.ensureAuthenticated fills the req parameter with the current user req.user.
Basically it does this: req.user = payload.sub; (with some other background stuff)
Then the req.user is available in the following functions e.g. clients.update, but not in clients.clientByID.
I know I could execute users.ensureAuthenticated in clients.clientByID again, but this would execute the code twice and be extra load on the server, right? I guess there must be another way, but I couldn't find anything in the documentation of express.
I'd like to know how I can access the req.user in clients.clientByID without executing the code in users.ensureAuthenticated twice.
Based on your question, I assume you would like to execute users.ensureAuthenticated before clients.clientByID is executed. This can be achieved by using the app.use functionality. app.use handlers will get executed before the app.param and app.route handlers.
For example:
var express = require('express');
var app = express();
app.use('/user', function(req, res, next) {
console.log('First! Time to do some authentication!');
next();
});
app.param('id', function(req, res, next, id) {
console.log('Second! Now we can lookup the actual user.');
next();
});
app.get('/user/:id', function(req, res, next) {
console.log('Third! Here we do all our other stuff.');
next();
});
app.listen(3000, function() {
});
I'm working on a small app running on the MEAN stack, and have hit an annoying snag: My backend app (Node with Express) is running at http://localhost:3000 and working just fine, but my frontend client app (Javascript with AngularJS) is running at http://localhost:8000, which means requests sent from Angular are received and responded to, but are rejected once they arrive because they're interpreted as coming from a different origin.
I was able to fix this with relatively little drama, by making my 'show me all the stuff' method look something like this:
exports.index = function(req, res) {
Region.find({}, function(err, docs) {
if(!err) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000');
res.json(200, { regions: docs });
} else {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000');
res.json(500, { message: err });
}
});
}
The res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000'); line is the one that I added to tell the browser it was fine to accept the response and stop bothering me about it; the problem now is that I have to add this stupid line to every single response that's sent from anywhere, and I'm convinced I must be missing some way to just change the default headers to include the Access-Control-Allow-Origin entry forever.
In a perfect world, I'd be able to flip this on and off based on what environment the code was being executed in, but I'd totally settle for a code block in app.js that I could at least remove one time instead of trying to track down 75 instances of res.setHeader. I figure there must be a way to change the .json method hiding behind res at its base, but the docs don't offer any insight into how I might do that, not to mention whether it's a terrible idea. Any thoughts?
edit
I thought (as was suggested) that configuring application-level middleware was the key. Here's the code that I added to my app.js file:
// allow CORS:
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000');
next();
});
This, however, yielded the same error ("No 'Access-Control-Allow-Origin' header is present on the requested resource.") as before.
Try this one as a middleware:
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
next();
});
I just ran into the same issue and tried the same snippet above. It did the trick.
// allow CORS:
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000')
next()
})
IMPORTANT: I had to place it above all other app.use(xyz) entries, just like #rev_bird mentioned he did with the CORS module. Try it.
you can make a common middleware using .use() or can use npm packages like express-interceptor also to intercept the response
I'm new to using Passport.js, but I find it's going pretty well so far. I'm using Passport with passport-local.
However, I want to require authentication for an entire directory excluding one page. So in my node server I'm serving up this direcory like so (using express):
app.use("/admin", express.static(__dirname + "/admin"));
And then I want to let the user hit /admin/login.html, so I wanted to do something like this:
app.get('/gb-admin/login.html', function(req, res){ });
Then I want to require authentication for the rest, so something like this:
app.get('/gb-admin/*', ensureAuthenticated, function(req, res){});
Here is my ensureAuthenticated function, for reference if it helps:
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/gb-admin/login.html')
}
How would I go about doing this? I've been generally sending things in infinite loops and causing the browser to timeout. Can anyone help?
The reason you're getting timeouts is because you can't have an empty route handler; at one point, you have to either return a response, or hand the request over the the next route handler/middleware.
That said, try this:
function ensureAuthenticated(req, res, next) {
if (req.path === '/gb-admin/login.html' || req.isAuthenticated()) {
return next();
}
res.redirect('/gb-admin/login.html')
}
app.get('/gb-admin/*', ensureAuthenticated, function(req, res, next) {
next();
});
// the static middleware needs to be declared after the route above, otherwise
// it will take precedence and ensureAuthenticated will never be called.
app.use("/gb-admin", express.static(__dirname + "/admin"));
I don't think there's a way to get it working with a separate route for the login page (unless you actually implement reading login.html and sending it back from without that routes handler), hence the check for it in the ensureAuthenticated middleware.
I wonder if it is your callback. Try:
app.get('/gb-admin/*', function (req, res, next) {
ensureAuthentication(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/gb-admin/login.html')
});
});
Passport.js offers great authentication for node.js and Express including a middleware solution:
ensureAuthenticated = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
return res.redirect("/login");
};
How can I use this middleware in the express-resource module? Unfortunately,
app.resource('users', ensureAuthenticated, require('./resources/users'));
doesn't work.
I know this is a little too late, and the original post was answered, however, I was looking for the same answer and found a solution I thought others might want to know.
Just make sure ensureAuthenticated is called from passport.
app.resource('users', passport.ensureAuthenticated, require('./resources/users'));
It is found here: https://gist.github.com/1941301
Workaround. Ensure authentication on all requests and ignore requests going to /auth and /auth/callback.
app.all('*', function(req, res, next) {
if (/^\/auth/g.test(req.url)) {
return next();
} else if (req.isAuthenticated()) {
return next();
} else {
return next(new Error(401));
}
});
You will need to do some magic in order to have each resource use the authentication middleware. The following gist explains how to accomplish this by using a menu structure.
https://gist.github.com/3610934
Essentially, you need the following logic:
app.all('/' + item.name + '*', ensureAuthenticated, function (req, res, next) {
next();
});
You could then in your menu structure specify what resources are protected, and if they require any kind of specific permissions, even down to the HTTP method level.
Hopefully this helps someone!
I'm not sure if express-resource has the option of inserting middleware into specific resources, but you could always insert checking if you are in that resource inside the middleware.
ensureAuthenticated = function(req, res, next) {
if (!/^users/.test(req.url) || req.isAuthenticated()) {
return next();
}
return res.redirect("/login");
};
This works:
app.get('/', ensureAuthenticated, admin.index);
As long as your strategy is setup correctly. I'm using the local strategy. Check out the guide:
http://passportjs.org/guide/username-password.html
I was looking up this topic as well, and found https://npmjs.org/package/express-resource-middleware. Haven't tested it, though.