javascript syntax while doing passport nodejs - javascript

I have a question on javascript syntax. Actually I came up with the coding while I was self-teaching MEAN stack tutorial (https://thinkster.io/mean-stack-tutorial#adding-authentication-via-passport). There is a very weired coding below.
})(req, res, next);
(req, res, next) seems arguments but no function utilize that arguments. Maybe I am not smart enough at this point so that I cannot see it.
Is there any guy who can help me on this? Thanks.
router.post('/login', function(req, res, next){
if(!req.body.username || !req.body.password){
return res.status(400).json({message: 'Please fill out all fields'});
}
passport.authenticate('local', function(err, user, info){
if(err){ return next(err); }
if(user){
return res.json({token: user.generateJWT()});
} else {
return res.status(401).json(info);
}
})(req, res, next);
});

To understand what's happening, you should know what "middleware" is in Express. It's a function that you can pass to Express that gets passed a request object, a response object, and a next function:
function middleware(req, res, next) {
...
}
With middleware, you can "tap" into the path that HTTP requests will follow through an Express application, and perform certain actions.
You might have already noticed that the middleware function signature looks a lot like your example code:
router.post('/login', function(req, res, next) { ... });
This is a route handler that gets called for POST requests to /login. Route handlers are similar to middleware, in that they get called with the same arguments and also perform certain actions (usually, next isn't used in route handlers, but it will still get passed as an argument).
You can "stack" middleware, too:
router.post('/login',
function (req, res, next) { ... }, // first middleware
function (req, res, next) { ... }, // second middleware
...
);
This is where next comes into play: if the first middleware isn't interested in the request, it can call next (which is a function) and the request will be passed to the second middleware (and if that middleware isn't interested in it, it can call next too, passing the request along all middleware in the app, until a middleware handles the request or it falls through, generating a 404 error, because there no middleware was found that could handle the request).
passport.authenticate() also returns a middleware function. It's usually used like this:
router.post('/login',
passport.authenticate(...),
function (req, res, next) { ... }
);
Which means that if you look at the stacking example, passport.authenticate() should return a function that accepts the three arguments req, res and next (and in fact, it does).
That means that the code above can be rewritten to this:
router.post('/login', function(req, res, next) {
passport.authenticate(...)(req, res, next);
});
Which matches the code in your question. Why you would want to call passport.authenticate() like that is a relatively advanced Passport topic.
EDIT: this is what passport.authentication, in very broad terms, looks like:
// a function that mimics what `passport.authenticate` does:
function myAuthenticate() {
return function (req, res, next) {
...some stuff...
next();
};
}
It's a function that returns a function. You can use it like this:
router.post('/login',
myAuthenticate(),
function (req, res, next) {
...
}
);
Which is (almost) the same as this:
router.post('/login',
function(req, res, next) { // <-- this is the function that got returned!
...some stuff...
next();
},
function(req, res, next) {
...
}
);

Related

Node + Express repeatedly firing/looping requests although result has been sent

I have tried almost everything, and my mind has now finally given up. Hence, I'm here asking for directions. How on earth can this simple piece of code (let's call it app.js):
var express = require('express');
var app = express();
app.use(function(req, res) {
console.log('Request made')
res.send('Hello World!');
});
app.listen(3000, function() {
console.log('Example app listening on port 3000!');
});
When run like node app.js result in the following outcome in my terminal, considering the fact that I've only hit localhost:3000 once:
Example app listening on port 3000!
Request made
Request made
Request made
Request made
Request made
Request made
Request made
...continues...
For some reason I end up with "Request made" being repeated again and again although the request is done and delivered to the browser.
The same is true if I use app.get('*', function(req, res) { ... }) instead of app.use(function(req, res) { ... }).
If I turn to something more specific, like app.get('/', function(req, res) { ... }) the repetition stops and I get one "Request made" as expected. However, I need to match all incoming requests - in my app I'm doing something way more complicated than logging "Request made" :)
Any ideas? Thanks!
Node: 8.11.2
Express: 4.16.3
You need to do something and then pass the results to next callback instead of sending a response which makes it recursive since it's intercepting a response and then doing the same causing a loop.
// this middleware will not allow the request to go beyond it
app.use(function(req, res, next) {
res.send('Hello World');
});
// requests will never reach this route
app.get('/', function (req, res) {
res.send('Welcome');
});
You need to call next() to invoke middleware
app.get('/', function (req, res, next) {
try {
// do something and return result
res.send('Welcome');
} catch(e) {
next(e)
}
});
app.use(function (err, req, res, next) {
console.log('Error occurred')
res.status(err.statusCode).send(err.message);
});

Hot reloading with express and chokidar causes a http headers sent error when using multiple routes

I've been trying a variety of setups for hot reloading and one that I've come across is the https://github.com/glenjamin/ultimate-hot-reloading-example/. Modifying this boilerplate code as a starting point, I've come across the following problem in my server code:
// server.js
import chokidar from 'chokidar';
import express from 'express';
const app = express();
// this is the middleware for handline all of my routes
app.use(function (req, res, next) {
require('./server/index')(req, res, next);
// if I commented out any additional routes, the setup would work fine
require('./server/foo')(req, res, next);
require('./server/catch-all')(req, res, next);
});
//this watches the server folder for changes
const watcher = chokidar.watch('./server');
watcher.on('ready', function () {
watcher.on('all', function () {
console.log("Clearing /server/ module cache from server");
Object.keys(require.cache).forEach(function (id) {
if (/[\/\\]server[\/\\]/.test(id)) delete require.cache[id];
});
});
});
app.listen(3000, 'localhost', function (err) {
if (err) throw err;
const addr = this.address();
console.log('Listening at http://%s:%d', addr.address, addr.port);
});
The above is the server code that handles clearing the cache by watching for changes with the chokidar module. If I have just one route required inside the app.use middleware function (which listens for every incoming request), I can get it to work. However if have multiple routes, the following error occurs:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
This is a common issue posted on stack overflow, but all of the solutions I've come across and attempted haven't worked. My route files are as follows:
//index.js
import express from 'express';
const router = express.Router();
router.get('/', (req, res, next) => {
res.send("greagrehgarhegrehuh").end();
return next('router');
});
module.exports = router;
//end of index.js
//foo.js
import express from 'express';
const router = express.Router();
router.get('/foo', (req, res, next) => {
res.send("foo").end();
return next('router');
});
module.exports = router;
//end of foo.js
//catch-all.js
import express from 'express';
const router = express.Router();
router.get('*', (req, res, next) => {
res.send("catch all").end();
return next('router');
});
module.exports = router;
// end of catch-all.js
All three routes do the same thing, bar the endpoint. So far I've explicitly called end on each to end the response, used return next('router') to skip the rest of the middleware functions and have also tried doing it without the above as well. Any ideas on what I'm missing here to get this working? Here's a github project that showcases the issue
https://github.com/RonanQuigley/express-chokidar-hot-reload
UPDATE
So I actually removed the next calls and seem to have almost got it working by doing the following:
app.use(function (req, res, next) {
require('./server/index')(req, res, next);
require('./server/foo')(req, res, next);
});
// a second app.use middleware, that does the same
// as the catch all // * router.get from my original post
app.use(function (req, res, next) {
app.get('*', (req, res) => res.send('catch all'));
})
However, I can't use this second app.use with another require call to a file with an express router like the others. So it seems that express runs through the middleware stack, reaches the * and tries to set the header twice.
The reason I need the * is normally if a user requests an endpoint that doesn't exist, Node correctly shows up with cannot GET/. However, for some reason, with the setup I've outlined express will then crash. My workaround is using * at the end of the middleware stack and I'd just use a res.redirect to send the user back to wherever, but this causes the above issue I've outlined in my original post. So not sure how to get around that one.
So currently I have either:
1) Hot reloading works without the require for a router.get('*'), but when the user navigates to an endpoint that doesn't exist, express will crash.
2) Hot reloading works with the app.get('*') inside a second app.use call, but I can't then use a router to move this into a separate file.
Okay, so posting this solution up for my own future reference and in case somebody else stumbles into this problem.
After speaking with the express devs, it turns out that this is indeed possible with a combination of the following:
// you need to use comma separated routes
app.use(
dynamic('./server/index'),
dynamic('./server/foo')
);
// require the library at runtime and apply the req, res, next arguments
function dynamic(lib) {
return function (req, res, next) {
return require(lib).apply(this, arguments)
}
}
In the case of webpack, this would break it as you can't use require as an expression. So use the following to get around that:
function createRoutes(router) {
const dynamic = (lib) => {
return function (req, res, next) {
// let webpack generate a regex expression from this require
// if we don't you would get a critical dependency warning
// which would result in the routes not being found
return require("./src/" + lib + ".js").apply(this, arguments);
}
}
router.use(
dynamic('index'),
dynamic('foo'),
);
return router;
}
Let's step back a bit and talk about middleware.
Say you have a function which runs some kind of middleware.
const runMiddleware = (req, res, next) => {
console.log(`this will run everytime a HTTP request comes in`);
}
Then to use that middleware within express:
app.use(runMiddleware);
Every time any (GET, POST, DELETE, etc) request comes in, this function is run.
Essentially you are doing the same thing below - You are wrapping three (3) route calls with a single function. This function is calling all of these routes at once, hence res is actually being sent 3 times in a row in the example below:
app.use(function (req, res, next) { // runs every time any request comes in
require('./server/index')(req, res, next); // res sent, ok
require('./server/foo')(req, res, next); // res sent, err
require('./server/catch-all')(req, res, next); // res sent, err
});
Here is a basic way of handling routes:
const index = require('./server/index');
const foo = require('./server/foo');
app.use('/', index);
app.use('/foo', foo);
// catch everything else
app.use(function (req, res) {
res.send('catch all');
})

Passportjs Callback, understanding arguments [duplicate]

This question already has answers here:
Understanding Passportjs Custom Callback
(3 answers)
Closed 6 years ago.
I'm having trouble understanding whats going on with the custom callback for Passport.js. I don't understand the (req, res, next) at the end. Should we have these values from closure?
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next); //<=== What is the purpose of this?
});
passport.authenticate() is a middleware. Briefly, a middleware is a function that modifies the request then passes it along to the next request handler. Request handlers in express are functions that take (req, res, next) as arguments. passport.authenticate, then, is a function which returns a middleware, which takes (req, res, next) as arguments.
Generally, it will be used like this:
app.get('/login', passport.authenticate());
whereby passport.authenticate() will modify the request, make sure the user is authenticated, then pass it along to the next handler.
In this case, we want passport.authenticate to do a little more, so we replace:
app.get('/login', passport.authenticate());
with the equivalent:
app.get('/login', function (req, res, next) {
passport.authenticate()(req, res, next)
});
and then more logic is added into the passport.authenticate constructor.
yes the (req, res, next) passes those values into your passport.authenticate function from the router context. If i were you i would also look into middleware for your router (express?) - its an easy way to add authentication to your routes rather than the granular way you are doing it here (would have to add that passport.auth into every route you wanted to authenticate).

How to obtain the next route's path in an Express app

I am catching all traffic before passing it forward using:
app.all('*', function(req, res, next) {
... run before stuff, related to the next req.route.path
next();
});
and I want to run some code before calling the next() function.
in order for me to know the proper code I need to run, I have to identify what is the next request route path.
Debugging current req object (inside all('*',.. ) does not giving any information about the next request.route.path
How can I get the next method route.path before calling it?
Your help will be appreciated. Thank you.
Instead of trying to look ahead, why not explicitly set middleware for the routes that need it?
var middleware = function (req, res, next) {
..run your code in here
};
app.get('/users:user_id', middleware, function(req, res, next) {
});
You can get the next route by checking the route when the response in the middleware has fired the finish event:
app.all('*', function(req, res, next) {
res.on('finish', function() {
console.log('Next route: ', req.route.path);
});
next();
});
For a route defined like this:
app.get('/users/:user_id', function(req, res) {
res.send('Hello');
});
You'll obtain the log:
$ Next route: '/users/:user_id'

How to have a NodeJS/connect middleware execute after responde.end() has been invoked?

I would like to achieve something like this:
var c = require('connect');
var app = c();
app.use("/api", function(req, res, next){
console.log("request filter 1");
next();
});
app.use("/api", function(req, res, next){
console.log("request filter 2");
next();
});
app.use("/api", function(req, res, next){
console.log("request handler");
res.end("hello");
next();
});
app.use("/api", function(req, res, next){
console.log("response post processor");
next();
});
app.listen(3000);
When I curl for the address, I get an exception to the console complaining about headers cannot be bothered after being sent which is fair enough. Only that I do not touch the response object.
/usr/bin/node app2.js
request filter 1
request filter 2
request handler
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:644:11)
at ServerResponse.res.setHeader (/home/zpace/node_modules/connect/lib/patch.js:59:22)
at next (/home/zpace/node_modules/connect/lib/proto.js:153:13)
at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:25:5)
at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:19:5)
at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:14:5)
at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
at Function.app.handle (/home/zpace/node_modules/connect/lib/proto.js:198:3)
Debugging the NodeJS/Connect layer I got into a part that somehow implies that if headers are already sent then executing a route handler must initialize response headers.
The question is if the above mentioned behavior is intentional (ie that the execution of any code after a route handler has finished sending a response is something utterly unimaginable or this is simply a bug in connect?
Not sure whether you have found your solution.
If you want to design a post-processor for the request cycle, you can use a middleware that listens to the "finish" event on the response object. Like this:
app.use(function(req, res, next){
res.on('finish', function(){
console.log("Finished " + res.headersSent); // for example
console.log("Finished " + res.statusCode); // for example
// Do whatever you want
});
next();
});
The function attached to the "finish" event will be executed after the response is written out (which means the NodeJS has handed off the response header and body to the OS for network transmission).
I guess this must be what you want.
I think this is a bad planning problem. You should solve this in a better way. I dont know why you have a request handler and a request post processor separated, but lets find out what we can do.
So yes, after response has ended you cant read the headers again.
So dont finish the response until the post processor is invoked.
var isEnd;
app.use("/*", function(req, res, next){
isEnd = false;
})
app.use("/api", function(req, res, next){
console.log("request handler");
res.write("hello");
isEnd = true;
next();
});
app.use("/api", function(req, res, next){
console.log("response post processor");
if(isEnd) {
res.end();
}
else next();
});
This is a kind of solution, but this may not be the best for your problem.
In my opinion it is really bad that you call next() after the response has been finished. If you need a post processor, why you do that in a request filterer (or what is this). Call a function but not next()
Maybe this:
app.use("/api", function(req, res, next){
console.log("request handler");
res.end("hello");
setTimeout(function(){(postProcessor(req)},0);
});
function postProcessor(req) {
//doing post process stuff.
//response not needed because already ended.
}
Or this:
app.use("/api", function(req, res, next){
console.log("request handler");
res.writed("hello");
setTimeout(function(){(postProcessor(req)},0);
// u cant res.end here because setTimeout.
//If you dont use setTimeout you can use res.end here, but not bot function.
});
function postProcessor(req, res) {
//doing post process stuff.
res.end();
}
The next() is not for that usage, what you uses.
I hope my answer helps you, but i know it not covers everything, but your answer is not really concrete too.
What a great question to try work out with your morning coffee!
So looking through proto.js, if you have a look down to line 102 which is app.handle which is the handler code for the middleware stack, you'll see how next() operates.
Where the function next() is called, you can see it checks if res.headerSent is true and if so it throws an error.
If modify line 14 to:
app.use("/api", function(req, res, next){
console.log("request handler");
res.end("hello");
console.log(res);
next();
});
You will see that it actually sets "headersSent" to true. So after we've ended the request, you can see from the next() code that it throws the error because of the conditions discussed.

Categories

Resources