I have to routes that I currently do like this:
app.all('*', passport.authenticate('facebook-token', { session: false }));
//Here goes specific routes.
app.get('/user/me',
(req, res, next) => {
next();
});
app.get('/user/makeRider',
(req, res, next) => {
req.user.user.makeRider(req.query)
.then((user) => {
next();
});
}
);
app.all('*', (req, res) => {
req.user.user.full().then((fulluser) => {
res.json({
user: fulluser,
params: req.query
});
});
});
They are responsible for authentification and output in my REST-api. The problem with these routes is that they make all routes valid, never throwing 404:s. Is there a better way of doing this, without adding the functions to every route?
This is not a setup that is common to Express (Restify has an option where you can call next() to transfer the request to a specific route, which would be your output handler, but that has its limitations as well).
Here's a possible workaround.
First, declare a output middleware:
let outputMiddleware = (req, res) => {
req.user.user.full().then((fulluser) => {
res.json({
user: fulluser,
params: req.query
});
});
};
Next, store a reference to the Passport middleware:
let authenticateMiddleware = passport.authenticate('facebook-token', { session: false });
And create a wrapper function to chain all middleware functions together:
let chain = (fn) => [ authenticateMiddleware, fn, outputMiddleware ];
Lastly, declare your routes like this:
app.get('/user/me', chain((req, res, next) => {
next();
}));
What this does is basically create route handlers that look like this:
app.get('/user/me', [
passport.authenticate(...),
(req, res, next) => { ...; next() },
(req, res) => { ...; res.json(...) }
]);
Related
I'm trying to understand how to use an application-level middleware (or at least usually used like this) like cookie-parser on route-level and conditionally.
I tried something like:
const myMiddleware = (req, res, next) => {
if (myCondition) {
return cookieParser();
} else {
next();
}
}
app.use('/admin', myMiddleware, (req, res) => {
res.sendStatus(401)
})
But it's not working, the request will be just stuck.
Is this possible?
Traditional cookie-parser implementation:
app.use(cookieParser())
cookieParser() returns a middleware function, i.e. a function that takes in req, res, next as arguments. You just have to pass it the arguments:
const cookieParserMiddleware = cookieParser();
const myMiddleware = (req, res, next) => {
if (myCondition) {
return cookieParserMiddleware(req, res, next);
}
next();
};
app.use("/admin", myMiddleware, (req, res) => {
res.sendStatus(401);
});
Notice that I'm creating the cookieParser middleware outside myMiddleware - technically we could also just do return cookieParser()(req, res, next) but recreating the same middleware again and again on every request would be wasteful.
I've also removed the else since the if block returns from the function (guard clause).
My function in the controller:
getWeather: (req, res) => {
const userId = req.params.userId;
weather.save().then(() => {
console.log('weather saved')
}).catch(error => { return res.status(500).json({ error }) })
}
The middleware in the model, here I want to get the userId as a param
weatherSchema.pre('save', function (req, res, next) {
console.log( req + ' pre!! '); //req
next();
})
I don't succeed, I tried to look for similar questions but their answers did not help me. What can I try next?
I guess you're confused between express middleware and mongoose middleware. The save mongoose middleware that you are using is a document middleware and it only gets a single parameter i.e. next and it is triggered before .save().
I guess an express middleware would solve your problem.
app.get("/someroute", (req, res, next) => {
// Here you have access to req.params.userId
next();
}, (req, res) => {
// Here you can save it to the db
})
Currently, I have the following code for many more oath provider:
// facebook
router.get("/facebook", passport.authenticate("facebook", { scope: ["email"] }));
router.get("/facebook/callback", passport.authenticate("facebook"), (req, res) => {
console.log(chalk.blue("went into facebook callback"));
res.redirect("http://localhost:3000/profile");
});
// github
router.get("/github", passport.authenticate("github"));
router.get("/github/callback", passport.authenticate("github"), (req, res) => {
console.log(chalk.blue("went into github callback"));
res.redirect("http://localhost:3000/profile");
});
Is there a way to unify that into an abstracted route? I.e. something like
// github
router.get("/:provider", passport.authenticate(:provider));
router.get("/:provider/callback", passport.authenticate(:provider), (req, res) => {
console.log(chalk.blue("went into {:provider} callback"));
res.redirect("http://localhost:3000/profile");
});
Update:
The following piece of code does what I want. Thx to #Usman Abdur Rehman.
function callbackDistributer(req, res, next) {
console.log(req.params);
global.provider = req.params.provider;
next();
}
router.get(
"/:provider/callback",
callbackDistributer,
(req, res, next) => {
passport.authenticate(global.provider)(req, res, next);
},
(req, res) => {
console.log(chalk.red("went into: " + global.provider));
res.redirect("http://localhost:3000/profile");
}
);
Have a middleware function going before the passport.authenticate middleware
function ownMiddleware(req,res,next){
global.provider = req.params.provider
next()
}
and then use it in the route handler as
router.get("/:provider/callback", ownMiddleware ,passport.authenticate(global.provider), (req, res) => {
console.log(chalk.blue("went into {:provider} callback"));
res.redirect("http://localhost:3000/profile");
});
I think it should work
This is my code when.
I am hitting put API it is executing middleware 3 times but it should execute for put API only.
app.use('/api/user', MiddlewareFun);
app.get('/api/user', (req, res) => {
//do something
});
app.use('/api/user', MiddlewareFun);
app.post('/api/user', (req, res) => {
//do something
});
app.use('/api/user', MiddlewareFun);
app.put('/api/user', (req, res) => {
//do something
});
please don't say use like this.
app.put('/api/user', MiddlewareFun, (req, res) => {
//do something
});
Well, it's happening, because you've made it to. If you want the middleware, to be executed at only selected method, you have to specify it. For example:
Instead of doing:
app.use('/api/user', MiddlewareFun)
app.put('/api/user', (req, res) => {
//do something
})
replace use method with put. As you'd bind regular route:
app.put('/api/user', MiddlewareFun)
app.put('/api/user', (req, res) => {
//do something
})
Also, one more thing. You don't have to duplicate your middleware call before every route declaration. If you want to apply a middleware to your whole router, you can use .use() (as you did), or .all(); which will result in the same behavior.
The middlewares in Express are binded to app or to router.
The solution to yuur problem is to check the method of the request object at the middleware
let MiddlewareFun = function (req, res, next) {
if (req.method === 'PUT') {
// do something
}
next()
}
app.use('/api/user', MiddlewareFun);
The answer is, You need to write express middleware which is part of your app or router. You can write as many middlewares you want, but in your case you just need it only once and here is the implementation of that.
const MiddlewareFun = function(req, res, next) {
// req is object which consist of information about request made.
// From req object you can get method name which is called.
if(req.method.toLowerString() === 'put') {
// your logic goes here
}
next();
}
app.use('/api/user', MiddlewareFun);
app.get('/api/user', (req, res) => {
//do something
});
app.post('/api/user', (req, res) => {
//do something
});
app.put('/api/user', (req, res) => {
//do something
});
I am using NodeJS, Express and Handlebars (template engine) to build a web application. Currently I'm trying to automatically redirect users whenever they enter an URL that does not exist (or whenever they might not have access to it).
The following returns the index page:
router.get('/', (req, res) => {
res.render('index/index');
});
But how do I make something like this:
router.get('/:ThisCouldBeAnything', (req, res) => {
res.render('errors/404');
});
The following example is from Github:
Say that I enter this URL:
https://github.com/thispagedoesnotexist
It automatically returns a 404. How do I implement this in my application?
Thanks in advance.
Use a middleware just after all route handlers to catch non existing routes:
app.get('/some/route', function (req, res) {
...
});
app.post('/some/other/route', function (req, res) {
...
});
...
// middleware to catch non-existing routes
app.use( function(req, res, next) {
// you can do what ever you want here
// for example rendering a page with '404 Not Found'
res.status(404)
res.render('error', { error: 'Not Found'});
});
After all your other routes you can add:
app.get('*', (req, res) => {
res.render('errors/404');
});
Alternately, you can use a middleware function after all your other middleware and routes.
app.use((req, res) => {
res.render('errors/404');
});
So you might end up with something that looks like:
//body-parser, cookie-parser, and other middleware etc up here
//routes
app.get('/route1', (req, res) => {
res.render('route1');
});
app.get('/route2', (req, res) => {
res.render('route2');
});
//404 handling as absolute last thing
//You can use middleware
app.use((req, res) => {
res.render('errors/404');
});
//Or a catch-all route
app.get('*', (req, res) => {
res.render('errors/404');
});
I see that you have express tagged. All you have to do is include a default handler that includes
res.status(404).render('404template')
For example
app.get('*', (req, res,next) => {
res.status(404).render('error.ejs')
});