I've just begun to work with NodeJS and I find myself puzzled on code such as
app.get('/home', function(req, res) {
// req and res are objects
})
I often see these kinds of function calls where the parameters in the anonymous function seem to come out of nowhere, yet contain various attributes and/or methods within?
You are passing a function to another function, this
function(req, res) {
}
is a function. Assuming you gave it a local variable name like b in the called method, the function could then be invoked. As an example, -
app.get = function(a, b) { // <-- assign a function to app.get
b("one", "two"); // <-- and then req would be one, and res would be two.
}
This is actually found here:
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
As you can see, express() is this and it is being used as a parameter to createServer.
You can find the documentation of createServer here:
The requestListener is a function which is automatically added to the 'request' event.
Then when you check the request event here:
Event: 'request'
function (request, response) { }
Emitted each time there is a request. Note that there may be multiple
requests per connection (in the case of keep-alive connections).
request is an instance of http.IncomingMessage and response is an
instance of http.ServerResponse.
Technically this event gets emitted every time a new request from a browser is received.
And this code
app.get('/home', function(req, res) {
// req and res are objects
})
Is somewhat a listener for a request to this route (check expressjs source code).
So req and res are short-hand of request and response and are passed from the request event.
Then express added some more methods/properties found here and here.
If you want to see the code for .get(), see here.
Related
I understand the essence of callback functions in that the function is executed again after being passed as the parameter to another function. However, I'm confused as to where the variables inside the callback function come from as shown in the following node.js example:
router.get('/', function(req, res){
res.render('index', {});
});
How do the variables req and res get populated? An example explaining how I can just call res.render(...) without declaring res myself would be greatly appreciated.
They come from the same place they come from when a normal non callback function is invoked, at invocation time.
If you have this function,
function add (a, b) {
return a + b
}
You're fine with knowing that a and b come from when you invoke add,
add(1,2)
and it's the same principle with callbacks, don't let your brain get all twisted just because it's getting invoked later.
At some point the function you pass to router.get is going to be invoked, and when it does, it will receive req and res.
Let's pretend the definition for router.get looks like this
router.get = function(endpoint, cb){
//do something
var request = {}
var response = {}
cb(request, response) // invocation time
}
In the case of your example, it's just up to node to pass your function request and response whenever .get is invoked.
The whole point of the callback is that the invoked function calls it back.
In the case of router.get, it will insert the route (path, method, callback) in a lookup table; when a request comes in, Express will construct the response object, match the request's path and method against all the entries in the lookup table, take the callback from the matching entry and invoke callback(request, response) (passing the detected request and created response).
They get populated by whatever code is calling the callback. In your example, this is something inside the Express framework, though Express uses the node http library under the hood and adds additional functionality to the request and response objects provided by it.
But in code you write you can create a callback function signature that takes whatever params you want.
I understand the essence of callback functions in that the function is executed again after being passed as the parameter to another function. However, I'm confused as to where the variables inside the callback function come from as shown in the following node.js example:
router.get('/', function(req, res){
res.render('index', {});
});
How do the variables req and res get populated? An example explaining how I can just call res.render(...) without declaring res myself would be greatly appreciated.
They come from the same place they come from when a normal non callback function is invoked, at invocation time.
If you have this function,
function add (a, b) {
return a + b
}
You're fine with knowing that a and b come from when you invoke add,
add(1,2)
and it's the same principle with callbacks, don't let your brain get all twisted just because it's getting invoked later.
At some point the function you pass to router.get is going to be invoked, and when it does, it will receive req and res.
Let's pretend the definition for router.get looks like this
router.get = function(endpoint, cb){
//do something
var request = {}
var response = {}
cb(request, response) // invocation time
}
In the case of your example, it's just up to node to pass your function request and response whenever .get is invoked.
The whole point of the callback is that the invoked function calls it back.
In the case of router.get, it will insert the route (path, method, callback) in a lookup table; when a request comes in, Express will construct the response object, match the request's path and method against all the entries in the lookup table, take the callback from the matching entry and invoke callback(request, response) (passing the detected request and created response).
They get populated by whatever code is calling the callback. In your example, this is something inside the Express framework, though Express uses the node http library under the hood and adds additional functionality to the request and response objects provided by it.
But in code you write you can create a callback function signature that takes whatever params you want.
I'm new to Node.js, so I'm still wrapping my head around asynchronous functions and callbacks. My struggle now is how to return a response after reading data from a file in an asynchronous operation.
My understanding is that sending a response works like this (and this works for me):
app.get('/search', function (req, res) {
res.send("request received");
});
However, now I want to read a file, perform some operations on the data, and then return the results in a response. If the operations I wanted to perform on the data were simple, I could do something like this -- perform them inline, and maintain access to the res object because it's still within scope.
app.get('/search', function (req, res) {
fs.readFile("data.txt", function(err, data) {
result = process(data.toString());
res.send(result);
});
});
However, the file operations I need to perform are long and complicated enough that I've separated them out into their own function in a separate file. As a result, my code looks more like this:
app.get('/search', function (req, res) {
searcher.do_search(res.query);
// ??? Now what ???
});
I need to call res.send in order to send the result. However, I can't call it directly in the function above, because do_search completes asynchronously. And I can't call it in the callback to do_search because the res object isn't in scope there.
Can somebody help me understand the proper way to handle this in Node.js?
To access a variable in a different function, when there isn't a shared scope, pass it as an argument.
You could just pass res and then access both query and send on the one variable within the function.
For the purposes of separation of concerns, you might be better off passing a callback instead.
Then do_search only needs to know about performing a query and then running a function. That makes it more generic (and thus reusable).
searcher.do_search(res.query, function (data) {
res.send(...);
});
function do_search(query, callback) {
callback(...);
}
The existing answers are perfectly valid, you can also use async/await keywords since ES2017. Using your own function:
app.get('/search', async(req, res, next) {
try {
const answer = await searcher.do_search(req.query);
res.send(answer);
}
catch(error) {
return next(error);
}
});
I have an API receiving an request and doing some querys and validation.
I want to use the response reference from the route inside the findUserPlayer function so I can send something to the client. The findUser function will return a data object that will be used on findUserPlayer.
var api = express.Router();
api.post('/signup', function (request, response) {
UserModel.find(req.body)
.then(findUser, createUser)
.then(findUserPlayer, createUserPlayer);
});
var findUserPlayer = function (data, res) {
//...
res.json(object);
};
I've tried calling findUserPlayer(data, res), which gives me 'data is not defined'.
I've tried calling findUserPlayer(res), which will override data.
How can I use the response object inside that callback?
Instead of directly passing findUserPlayer function as a success handler, you can define a success handler function while will then call findUserPlayer.
var api = express.Router();
api.post('/signup', function (request, response) {
UserModel.find(req.body)
.then(findUser, createUser)
.then(function(data) {
return findUserPlayer(data, response);
}, createUserPlayer);
});
var findUserPlayer = function (data, res) {
//...
res.json(object);
};
JavaScript is a very flexible language which means there are many ways you can handle this, one of the easiest (in terms of minimum code change) is to reverse the order of arguments in findUserPlayer and binding your context (.bind(response)).
But that would be a poor design choice. There's no reason for a function that "finds a user" to deal with responses or json. It's out of this functions scope and responsibility. The request handler is the one that should deal with formatting a relevant response, and I'd do that by returning the relevant data in the promise chain and eventually:
.then(function(data) {
response.json(data);
});
I'm a big fan of lodash and sometimes to a fault, but thought I would add the following using lodash's partialRight function.
var _ = require('lodash');
...
UserModel.find(req.body)
.then(findUser, createUser)
.then(_.partialRight(findUserPlayer, response), createUserPlayer);
_.partialRight returns a new function with the partials appended to the new function. The first argument of _.partialRight is the function we want to append the arguments to. The subsequent arguments are the args we want to append to the function.
I'm assuming the following function signature: findUserPlayer(data, response). _.partialRight appends the response object to the new function. The new function signature looks like this now: function (data).
documentation
I'm new to Node and Express and the other layers that go along with building web apps with node and the request and response parameters are really confusing me. My confusion lies in the fact that those two parameters are often present in a function but oftentimes one or both of them isn't declared. Also, much of the time an additional parameter will be thrown in, like 'next' or something else. For example, I have the following router for an API:
router.route('/teams')
// create a team at POST http://localhost:8080/api/teams
.post(function(req, res) {
var team = new Team();
team.name = req.body.name;
team.location = req.body.location;
// save the new team and check for errors
team.save(function(err) {
if (err) {
res.send(err);
};
res.json({ message: 'Team created!' });
});
})
// GET all the teams at GET http://localhost:8080/api/teams
.get(function(req, res) {
Team.find(function(err, teams){
if (err) {
res.send(err);
};
res.json(teams);
});
});
Both .post and .get call a function with req and res as parameters, but req is never used. So how does the function know what to do with req or res if they're not defined and used or not used in completely different orders? Or if I named them something completely different?
What exactly is happening with requests and responses? Sorry for my ignorance. I've read the documentation but it's not clicking.
Thanks.
When you use expressApp.use('/some/route', myRouteHandler); Express will listen for requests for that route, and when it's hit, it will call the function you provided (callback). It will give it three parameters: request and response, and next. (Actually could be four, but lets keep things simple.)
So, your callback might be defined like this:
function myRouteHandler(a, b, c) {
// do stuff
};
or like this:
function myRouteHandler(req, res, next) {
// stuff
}
or simply:
function myRouteHandler() {
// stuff
}
Whatever you do, doesn't matter. When the app is started, express listens for requests.
When one of them matches the route (/some/route), express will, in its internal workings, call the function you provided, like this:
myRouteHandler(requestObject, responseObject, nextMiddleware);
So in the first case, you can access the request (like, request headers, full url, caller IP address or similar) by using req. In your second case, you'll access it by calling a. In the third case, you can use arguments[0].
By convention, people will use the form: myCallback(req, res) and know that Express will put the request object as the first param, and response as the second. The response object actually has a method end(), so you can end the request. If there is also a next() object, you can call the next middleware.
Say you have a route defined like this:
app.use('/api/users', checkAuthorizationHandler);
app.use('/api/users', makeSureTheIPisFromOurInternalNetwork);
app.use('/api/users', nowHandleTheResponse);
Each of those handlers gets a third param. If you name it, you'd usually in your function declaration call it 'next' parameter. It means, the next function in order.
Say your function checkAuthorizationHandler(req, res, next) will check for req.headers('auth') token and if it's ok, it will in the function body, call next().
Then the function makeSureTheIPisFromOurInternalNetwork(a, b, c) is called. It will check that the a.ip is a LAN ip address and call c();
Finally your function nowHandleTheResponse() will find all users, and respond with a JSON object of the users: arguments[1].json([user1, user2, user3]);
So, first param is something that express gives you, it's the request, second is response, third is a next middleware function in line. No matter what you call them, they are there.
P.S. You can also declare your middleware with four params:
function(error, req, res, next);
Express will actually check your function and if it finds that you have four params and not two or three, it will give you any errors thrown by the middleware that ran earlier in the chain. Meaning, if your checkAuthHandler says next(new Error('Not authorized'));, your next function might check for that error, and if it's present, not give results. Often however will the middleware which detects errors just res.end('some error message');
If I haven't confused you enough, just say, I've got more where this came from :)
It is the framework convention. The first argument is the request, the second is the response. If you're declaring a middleware (.use), the third argument is the next middleware in the chain.
You can name these variables however you want, as long as you know the order. You could have something like: .post(function(a,b) {}); and then the request is represented by variable a, and response by variable b.
If, for whatever reason, you don't need the request, only the response, you still have to have a first argument, as the response is represented by the second argument.
In javascript, there's no method overload like in Java, for example (maybe here's where you getting the confusion from). A function is represented by its name, not how many arguments it takes. Here's a simple example:
function logToConsole(level, message) {
if (!message) {
message = level;
level = 'INFO';
}
console.log('['+level+']', message);
}
logToConsole('My message'); // prints out: "[INFO] My message"
logToConsole('WARN', 'My message'); // prints out: "[WARN] My message"
Did you notice how we defined a default value for level, based on the existence of message?
Hope this clarifies things a bit.
Request, response and next are passed to all middleware functions. The request object contains information about the HTTP request, and the response object is used to handle the request. The Expressjs documentation details these objects. The next() call is used in something called the dispatcher, a middleware function may or may not call next() depending on usage. Next simply calls the following middleware.
Here is an example of using next():
function helloWorld(req,res,next){
console.log('Hello, world!');
next();
}
// This function doesn't call next(), therefore it will
// not call the subsequent middleware in the dispatcher
function goodbyeWorld(req,res,next){
console.log('Goodbye, world!');
}
app.use(helloWorld);
app.use(goodbyeWorld);
Output:
Hello, world!
Goodbye, world!
Now let's reorder the middleware
app.use(goodbyeWorld);
app.use(helloWorld);
Output:
Goodbye, world!
The helloWorld function is not called. Notice the importance of middleware order and the next() function call.