Sharing a response object within a module, without passing as param - node.js

If I assigned the res (result) object to a module level property, will it be unique for each request, or could a secondary request that is started before the callback finishes overwrite it?
var moduleData = {};
router.route('/publishers/:id')
.get(function(req, res) {
var id = req.params.id;
// Assigning the res property to a module level property called `moduleData`
moduleData.res = res;
db.findById('publishers', id, function(error, publishers) {
someFurtherWork(publishers); // would rather not pass the res object around
});
});
function someFurtherWork(publishers) {
someWork(publishers, function(error, data) {
// NOW we send the data back to user... is `res` guranteed to be the same one that initiated the request?
moduleData.res.send(data);
});
}
The router is itself event driven, meaning that each .get() request is handled as a callback to the server, when the thread is available. This guarantees each response object is unique to the function. Will a module level property be overwritten by a second GET request here?
If so, what workarounds are there, because I don't want to pass around my response object to multiple chained callback functions, that don't use them until all the data is collected.
There's a good reason I'm doing this, because if I have a bunch of callbacks, and once they're all done, then I need my response object. I figured if I used the response as a module level property, it won't need to be passed around.

The unique scope of each request your app receives is the same as the scope of the first callback you provide to the router, any variable that is defined in the outer scope is global to all requests.
You have to move the declaration of your var ModuleData = {} to the top of the callback. And because you defined someFurtherWork(publishers) function inside the same callback then it will have access via the closure to ModuleData object and you can just use it.
And if what you only need is to have the res object available to your nested callback and function so you can just use it as long as they all have a common root scope which is the initial callback function. Aren't closures awesome!

Related

Accessing variable in parent scope

I have a custom logging function which is assigned to express requests req.log object using middleware.
The purpose of this is for the logging funtion to be able to read the request headers.traceid, before transmitting the log event to a seperate service.
This is working perfectly fine using middlware or with an extra parameter in the function, however to simplify the use of it.
What I'd really like to know if there's a way for the function to be able to read the req object from the scope it was called in, without referencing it either using middlware or as a function paramter?
// log.js
module.exports = () => {
console.log(...arguments)
const req = getVarFromParentScope("req") || undefined
const traceId = req?.headers.traceid || null
// POST { timestamp, traceId, args: { ...arguments } } to logging service
}
No, it isn't.
(And if it was, then the ability for a function to access a variable inside another function just because it was the calling function would make it very easy to write code that was very hard to debug.)

Understanding middleware in Express

I am trying to figure out how middleware works in Express.
Whilst I understand the concept of middleware, I am confused by the middleware parameters.
Here is an example from the offical docs regarding middleware:
app.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
In this example, I can see there are two functions that act as two middleware which are executed one after the other before this specific route is handled.
But what are the parameters passed to these functions?
Are req and res just "empty" objects?
If so how are we able to reference the property req.originalUrl?
And if not, where is that object and its properties coming from?
They also use res.send in the tutorial, so therefore the res object seems to also have properties and not be an "empty" object.
(I understand that next is a call back argument).
Summary
The request object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.
The response object represents the HTTP response that an Express app sends when it gets an HTTP request.
Middleware functions are functions that have access to the request object, the response object, and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.
Routes can have chained methods attached (for GET, POST and DELETE requests) that take middleware functions as arguments.
The request object is the data initially received from the request, which can be modified as it passes through various middleware functions, and the response object is the data sent out.
Example Middleware
Below is an example middleware function you can copy and paste at the beginning of your app:
/**
* An example of a middleware function that logs various values of the Express() request object.
*
* #constant
* #function
* #param {object} req - The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on. In this documentation and by convention, the object is always referred to as req (and the HTTP response is res) but its actual name is determined by the parameters to the callback function in which you’re working.
* #param {object} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request. In this documentation and by convention, the object is always referred to as res (and the HTTP request is req) but its actual name is determined by the parameters to the callback function in which you’re working.
* #param {Function} next - `next` is used as an argument in the middleware function, and subsequently invoked in the function with `next()`, to indicate the application should "move on" to the next piece of middleware defined in a route's chained method.
* #see {#link https://expressjs.com/en/4x/api.html#req|Express Request}
* #see {#link https://expressjs.com/en/4x/api.html#res|Express Response}
* #see {#link http://expressjs.com/en/guide/writing-middleware.html|Writing Middleware}
*/
const my_logger = (req, res, next) => {
console.log("req.headers: ");
console.log(req.headers);
console.log("req.originalUrl: " + req.originalUrl);
console.log("req.path: " + req.path);
console.log("req.hostname: " + req.hostname);
console.log("req.query: " + JSON.stringify(req.query));
console.log("req.route: " + JSON.stringify(req.route));
console.log("req.secure: " + JSON.stringify(req.secure));
console.log("req.ip: " + req.ip);
console.log("req.method: " + req.method);
console.log("req.params:");
console.log(req.params);
console.log("==========================");
//if next() is not invoked below, app.use(myLogger) is the only middleware that will run and the app will hang
next();
}
// called for all requests
app.use(my_logger);
Example Routes
Below are some example routes.
The routes have chained methods attached that take middleware functions as arguments.
// some example routes
app.route("/api/:api_version/pages")
.get(api_pages_get);
app.route("/api/:api_version/topics")
.get(api_topics_get)
.post(api_login_required, api_topics_post)
.delete(api_login_required, api_topics_delete);
app.route("/api/:api_version/topics/ratings")
.post(api_login_required, api_topics_ratings_post);
Using next() in a middleware function
In the above example, you can see some methods have two middleware functions as arguments.
The first one, api_login_required, verifies login credentials and, if successful, calls next() which prompts the next middleware function to run.
It looks like this:
const api_login_required = (req, res, next) => {
// req.user exists if the user's request was previously verified, it is produced elsewhere in the code
if (req.user) {
next();
} else {
return res.status(401).json({ message: 'Unauthorized user!' });
}
}
Middleware without next()
However, the get() method attached to the route handler for /api/:api_version/pages only has a single middleware function argument: api_pages_get.
As shown below, api_pages_getdoes not call next() because there are no middleware functions that are required to run after it.
It uses the send() and json() methods of the response object to return a response.
const api_pages_get = async (req, res) => {
var page_title = req.query.page_title;
var collection = mongo_client.db("pages").collection("pages");
var query = { page_title: page_title };
var options = { projection: { page_title: 1, page_html: 1 } };
try {
var page = await collection.findOne(query);
// if there is no result
if (page === null) {
res.status(404).send('404: that page does not exist');
return;
}
// if there is a result
else if (page !== null) {
res.json(page);
return;
}
} catch (err) {
console.log("api_pages_get() error: " + err);
res.send(err);
return;
}
}
Notes on middleware
Some other notes I've previously written for my own reference that may help:
Middleware, or middleware functions, have access to the Express request and response objects and are passed as arguments to a route's chained method (or on all requests if passed as an argument to an instance of the use() method defined early in your code).
next is used as an argument in the middleware function, and subsequently invoked in the function with next(), to indicate the application should "move on" to the next piece of middleware defined in a route's chained method.
If a middleware function does not invoke next(), it will not move on to the next piece of middleware defined in a route or method handler.
Additionally, if next() is not used, and a terminating action, ie a response, is not defined in the function, the app will stay in a "hanging" state.
Do req and res are just "empty" objects?
No, req and res are never empty and are in fact same which are passed on to each middleware. You can also modify the req and res objects and the modification will persist in all next middlewares.
You can see all the available fields on req and res here respectively - request object and response object.
You can always access req and res at any point in a middleware. If you wish to the end the request response cycle, you can just use the response object and send a response like res.send(200). This will end the req-res cycle and you need not call the next().
But what paramters are given to this functions ?
You don't need to pass any parameter to this function. Express will alwasy pass the req, res and next to any middleware defined. It's the format you can assume that express uses and and all middlewares should follow.
Note that if you don't end the req-res cycle, you must call the next() which will pass on the control to the next middleware. If the middleware does not end the req-res cycle and also does not call next(), the request will keep hanging and may perhaps just timeout on the client side.
If I understand you correctly, the confusing part are the objects passed to the middleware functions? In the docs you've linked there is already an explanation for those (See below).
"But what paramters are given to this functions ?."
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
(Source)
"Do req and res are just "empty" objects ?, if so how come we are using the field req.orginaleUrl ? and if not where is that object and
its field came from ?"
If you follow the links, you'll discover following explanation for the request object:
The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.
(Source)
The originalUrl property mentioned in your question is a property of the req object.
and the response object:
The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
The send is a method assigned to the res object, which will send a HTTP response.
(Source)

LoopBack accessToken in invoked method observer

I have two LoopBack models, A and B. Part of their code is like this:
A.beforeRemote('create', function (ctx, unused, next) {
...
B.findById(idForB, callBack);
...
});
B.observe('access', function (ctx, next) {
const token = ctx.options && ctx.options.accessToken;
const userId = token && token.userId;
ctx.query = ctx.query ? ctx.query : {};
ctx.query.where = ctx.query.where ? ctx.query.where : {};
ctx.query.where.allowedUserId = userId;
});
Now, B's access observe hook has accessToken when REST calls are directly made from B/ API.
However, when making an API POST A/ API call, A's beforeRemote hook on create attempts to call B.findById which in turn triggers B's access observe hook, but in this scenario, there is no accessToken; not even option.
How do I propagate access information from A to B?
You pass it along in the options argument. As mentioned below, if you're doing something custom make sure the options.accessToken is set or set it yourself. findById etc already have the mechanism to provide the options-object.
https://loopback.io/doc/en/lb3/Using-current-context.html
Any additional context is passed in the “options” argument. Built-in
methods such as PersistedModel.find or PersistedModel.create already
accept this argument, custom user methods must be modified to accept
it too.
Whenever a method invokes another method, the “options” argument must
be passed down the invocation chain.
To seed the “options” argument when a method is invoked via a REST
call, the “options” argument must be annotated in remoting metadata
with a specific value set in the “http” property.
Optionally, applications can customize the value provided to “options”
when invoked via REST.

iron-router template data in rendered callback

I'm passing a data object to a template with iron-router but would like to access the data within the Template.name.rendered = function() { ... } callback.
From Meteor data-context with iron-router I've tried UI.getData() but receive an error There is no current view. Using this.data returns null.
How can I get access to the data object passed to the template from the rendered callback?
You were on the right track with looking for the data context, but this is actually how you get access to it:
var ctx = Template.currentData();
Also, I believe Template.x.rendered is about to be deprecated, so if that doesn't work, try using
Template.x.onRendered(function() {
var ctx = Template.currentData();
console.log(ctx);
});

Differentiate between nodejs request and response

There is a generic structure of nodejs callback functions :
function(req,res){
//handle callback
}
I just want, callback should work correctly even if sometimes i write in mistake (res, req)
Given mixture of req or res, how do i find which one is actually request and which one is response.
req is an IncomingMessage object and res is a ServerResponse object.
So check for unique properties on each, for example if the particular object has a writeHead() function, then it's the response object.
You may also be able to use instanceof to check: res instanceof http.ServerResponse.
Functions in JavaScript are not programmatically prototyped by parameter names. The length property of a function only provides the number of parameters specified in the definition:
var fn = function (one,two,three) { return "x"; };
console.log(fn.length); // 3
Although there are ways to retrieve these names (see this question), usually procedures simply ignore how you name the parameters of your functions/closures, and instead assume that you are following the proposed API.
For this reason, it remains as the best practice to pay attention to the API and name parameters accordingly. In a Node.js HTTP request listener, the request comes always before the response (it is documented and many examples are available). As mentioned by other answers, you can dynamically check whether the request is an http.IncomingMessage or whether the response is an http.ServerResponse, but it seems to me that you can avoid introducing an overhead just with proper naming.
With that said, given the variables req and res, it is easy to make a check at the top of a function body, like the code below. However, do note that this would only be remedying what can be prevented by just following the API contracts, and as thus I cannot recommend it (unless you really want to make functions with a more flexible API).
function(res,req) {
if (req instanceof http.ServerResponse) {
// wrong order, swap.
var t = req;
req = res;
res = t;
}
// handle request
}

Resources