What is the best way to structure the logic in an ExpressJS API.
So lets say I want to create a register and login function, and lets say I want a user to be logged in when he is successfully registered.
Now there are different ways I can achieve this, my question is then essentially: Which method is best and why?
METHOD 1
Everything is middleware:
router.post('/path', someMiddleware, register, login, function(req, res){
//You are registered and logged in.
});
So here both the register and login is treated as middleware, with both of them ending with a call to next(). This also results in the best reusability, because I can call either login and/or register again in any other express routing.
METHOD 2
Register is middleware and calls login (which is now just a standard function):
router.post('/path', someMiddleware, register, function(req, res){
//You are registered and logged in.
});
So here register is still middleware, but just before calling next() it calls login() which in this case is not middleware. The problem here is that if user that is already registered wants to login, should I create a hybrid login function that is also middleware and just call it in that specific post request?
METHOD 3
Logic is not in middleware and gets called in the wrapper:
router.post('/path', someMiddleware, funcWrapper(register, login), function(req, res){
//You are registered and logged in.
});
and then (in pseudo):
funcWrapper(actions...){
foreach actions
action()
}
Here logic and middleware are split, there is a wrapper that loops through all the functions that are passed in as parameter (in this case register and login)
Just a last question:
If I haven't asked enough questions, I have a last one. Is it better practice to end all express routing calls with
..., function(req, res){
//response
});
or with
..., lastMiddleware);
and then in the lastMiddleware there is some response
Related
I have a third party who wants to send a form via POST to my website to preset some inputs.
A POST is also used to finalize the form and process data when all fields have been provided.
The form should be CSRF-protected when the user submits it and data is to be processed server-side but should skip CSRF token check when the third party initially sends some data.
What's a clean way to bypass CSRF verification based on the data sent to a specific route and HTTP verb/method when using csurf?
One way I see is to work around this by using different route endpoints, but is there a more direct solution?
You may find you answer in here: Calling a middleware from within a middleware in NodeJS/ExpressJS. The thing is to implement a middleware which would call the csrf middleware in conditions match, or else directly call the next middleware with next().
Example:
app.use('my-route', (req, res, next) => {
if (condition) {
return csrfMiddleware(req, res, next);
} else {
return next();
}
});
If you want to use this middleware for a specific verb, replace app.use with app.<verb>. For example, app.get is pretty much a middleware checking for get verb.
Using passport.js, what is the recommended way to check if a user isAuthenticated?
I see examples of people doing things like this:
app.get('/', isAuthenticated, function(req,res){});
How does this even work, app.get only accepts two arguments?
What about when I use express.Router()?
What's the correct syntax for router.get?
More generally, checking isAuthenticated at every route seems inefficient. Is there a better way to check authentication in an Express app?
Thanks.
app.get accepts as many middlewares as you need. According to the documentation:
router.METHOD(path, [callback, ...] callback)
...
You can provide multiple callbacks, and all are treated equally, and behave just like middleware, except that these callbacks may
invoke next('route') to bypass the remaining route callback(s). You
can use this mechanism to perform pre-conditions on a route then pass
control to subsequent routes when there is no reason to proceed with
the route matched.
This is how your authentication middlware function may look like:
function isAuthenticated(req, res, next) {
if(/*check authentification*/) {
return next();
}
res.send('auth failed');
}
On the other hand passport.js provides a built-in function that can be used as Express middleware.
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/users/' + req.user.username);
});
Authenticating requests is as simple as calling passport.authenticate() and specifying which strategy to employ. Strategies must be configured prior to using them in a route. Continue reading the chapter on configuration for details.
So I am running some API tests and I noticed that one test is failing because it is running some parameter handling logic before middleware, now here is an example of the route definition:
app.post("/something/:some_param",
middlewareA, middlewareB, middlewareC,
function(req, res) {
// Do stuff
});
Now I assumed (wrongly I think) that middleware would be invoked first then it would handle the parameter handler for :some_param however it seems to be the other way around. (by parameter handler I mean app.param())
Problem I have here is that if the above is correct and parameter handlers are run first, some of the logic within the parameter handler assumes the user is logged in already and blows up if they are not, and middlewareA handles user authentication and if they are not logged in redirects them etc, so ideally I would want middlewareA to be called first, so is there a way to achieve this ordering?
The only way I could see this working would be if the parameter handler could utilize middleware but there is no documentation on the API docs on this subject, so is there any best practice to handle this sort of scenario? as I do not want to have to shoe horn my middlewareA logic into my :some-param handling logic as I also have many other :other-param handlers etc which would also need this authentication (and other) middleware run before they run.
Yes, param handlers run before middleware. You can deal with this by either:
recoding your param handler as a middleware. There's not that much difference between the 2 mechanisms.
OR, in your param handler, just run the desired middleware directly as below:
.
function someParam(req, res, next, paramValue) {
myAuthMiddleware(req, res, function (error, result) {
if (error) {
next(error);
return;
}
//Here the user will be logged in
// do what you need to do with req and paramValue
next();
});
}
I'm working on an API using restify. There will be a dozen or more endpoints and each one requires authentication. The API will be stateless, so each API request, regardless of endpoint, will pass credentials.
What I'd like to do, if possible, is to authenticate before negotiating the route. Otherwise, if I have a route:
server.get('/activities', activities.index);
Then, within activities.index (and every other routing method), I have to duplicate the following:
var user = require('../models/user')(server);
user.authenticate(req.authorization, function(err, user) {
...
// Do the real activities-related stuff.
});
This is one of those things where it feels like there must be a better way of doing it, but I don't know what it is.
Anyone have any thoughts?
So you can register handlers to be ran before every route is ran.
http://mcavage.me/node-restify/#Common-handlers:-server.use()
server.use(function(req, res, next){
//do authentication here
if(authenticated){
return next();
}
else{
res.send({auth:false});
})
So when you use server.use when the user asks for /activites it will run all of the server.use you created in the order you created them before running the code for the route.
I have a simple app, built with the help of node.js and express. This app has multiple routes and basic login/logout mechanics. I want all routes to redirect to a login form if the user is NOT logged in. This can be done by inserting auth checker lines into each route file.
The question is :
Is it possible to chain the routes to push all requests through login checker route and then pass it to the requested one without writing anything to existing route files?
E.g. existing routes are "/", "/upload", "/login", "/logout".
I want the request to get or post "/upload" to be first processed by "/login" route and then by "upload" route.
Yes, you can chain handlers in a route. Your handler definition should be like
routehandler(req, res, next){
//send response directly
//or call next to call the next handler
}
You can then put multiple handlers in the order you want:
app.get('/server', ensureAuthenticated, housekeeping, routes.server.get)
Here ensureAuthenticated and housekeeping dont send the response just call next(). The last one returns the resulting page.
Please see you would want a different handler than what you use for login. Login page would do authentication, rest pages should just check if the user is authenticated or not. The difference would be clear if you are using sessions.
The args for the route handlers are the same as that of middlewares. Those are :
(err, req, res, next) Error handlers
(req, res, next) Non-error handlers
A trivial variation of above is that next can be left out if it is the end function you want in callback chain. You cannot have other args apart from these. You can see the how they are called here (line 154).
A route consists of method, route-match and callback array. Like the middlewares the callback chain is executed sequentially for a specific route until response is returned or error is thrown.