Override express route handler - node.js

I'm trying to redefine a express route handler
I have something like
var x = {
handle: function(req, res){
res.send("first");
}
}
app.post("/handle", x.handle);
setTimeout(function(){
x.handle = function(req, res){
res.send("second");
}
}, 2000)
but this doesn't change the way that route handles requests.
How can I achieve something like this?

A simplest fix is to ensure x.handle is always retrieved. In your approach, the function reference is retrieved once, when you attach it but then when you set the reference to point to another function, the post handler still points to the old one.
Attach then
app.post("/handle", (req, res) => x.handle(req, res) );
This method always asks x for current value of the handle method and you are free to reattach it to anything you want.

why it doesn't work
when you pass x.handle into a method, as a callback, you are not passing a reference to x at all. you are only passing handle around.
later, when you change x.handle, you are changing the handle method for x as expected. but, the previous reference to x.handle as a parameter to your post method is unchanged, because this call to post knows nothing about x. it only knows about the handle method that you passed in.
how to fix it
there are a lot of ways to fix this, depending on how you really want to handle things.
if you just need a timeout, then something like this would work:
var count = 1;
app.post("/handle", function(req, res){
if (count === 1){
setTimeout(function(){
count += 1;
}, 2000);
// do the first thing here
} else {
// do the second thing here
}
});
if you don't need the timeout, you could just increment the count
again, there are a lot of ways to do this... but you will have to include the logic of deciding which one to do, inside of the route handler function directly.

Related

ExpressJS - function returning undefinded

function checkFamilyStatus() keeps returning undefined for some reason, when it should be returning a boolean value from a mongodb collection.
A bit of context here - I decided to separate the logic part from the router methods like get and post methods, so as to make it look clean and understandable like in functional programming. So I put the logic part in functions and invoke them inside the router methods, but it doesn't work out. Besides, I don't know if this is a good practice or not. Wouldn't it be much easier to read if done like this, instead of say, putting a whole bunch of code in one place?
I've been stuck on this piece of code for a while. I am a bit confused on the working of asynchronous JS as a whole. I did some research, but still don't understand why this wouldn't work. Could someone clarify this up for me?
// post method
router.post("/create", ensureAuthenticated, async(req, res) => {
let userID = req.user.id;
console.log(await checkFamilyStatus(userID)); // but returns undefined
// rest of the code
}
// check family status
checkFamilyStatus = async userID => {
Account.findOne({
_id: userID
}, (err, account) => {
return account.hasFamily; // should return boolean value ?
});
};
Assuming the logic behind account.hasFamily is correct, then you need to await for the return, so it should be return await account.hasFamily;

Correct use of express in Node js

const express = require('express');
const app = express();
app.set('view engine', 'ejs');
app.listen(10000);
function function_a(inp)
{
var tmp_var = inp;
console.log(tmp_var)
//10 - the first time
//20 - the second time
app.get('/pageno1', (req, res) => {
res.redirect('...');
//..
console.log(tmp_var) //10 - on both calls
//..
});
}
function start(/* .. */)
{
//...
function_a(10);
function_a(20);
}
Suppose that I have two functions that simplified look something like the above. My issue is that the tmp_var holds the same value on both calls inside the app.get('/pageno1') even though I pass a different value.
Two points I would like to bring your attention to;
a) I dont use next(); (I am not sure if thats the issue),
b) I dont have a 'default' page (app.get('/', ...)) because I didnt need it (kinda weird, but thats my case.) I dont mind adding one, if thats the issue.
EDIT:
What is the expected end result: Get the URL parameters passed onto a URL and (eg: example.com/route?=<...>) and redirect the user to a page. After that is done in my code, in another function, use a stored variable and do some other things, using the parameters gotten from the URL and the stored variable. Wait for next GET request.
What I tried:
app.get('/pageno1', (req, res, next) => {
res.redirect('https://..');
//when that is done, move to another function
//here comes the issue (that other function needs the stored variable)
//and although its not needed inside `app.get` I need to pass it to the
//function after thats done.
function_A(param, req.query);
});
function_A(inp1, inp2)
{
//do some things
}
If that can be done using native HTTPS module, I don't mind not using express.
Lastly in case its not clear, I want to pass the local variable in the other function (function_A). So not necessarily inside the /pageno1 request. But, AFTER the pageno1 request is done, I need both the local variable and the req from the request to call the function_A.
If you need better explanation in anything, feel free to ask!

Block function whilst waiting for response

I've got a NodeJS app i'm building (using Sails, but i guess that's irrelevant).
In my action, i have a number of requests to other services, datasources etc that i need to load up. However, because of the huge dependency on callbacks, my code is still executing long after the action has returned the HTML.
I must be missing something silly (or not quite getting the whole async thing) but how on earth do i stop my action from finishing until i have all my data ready to render the view?!
Cheers
I'd recommend getting very intimate with the async library
The docs are pretty good with that link above, but it basically boils down to a bunch of very handy calls like:
async.parallel([
function(){ ... },
function(){ ... }
], callback);
async.series([
function(){ ... },
function(){ ... }
]);
Node is inherently async, you need to learn to love it.
It's hard to tell exactly what the problem is but here is a guess. Assuming you have only one external call your code should look like this:
exports.myController = function(req, res) {
longExternalCallOne(someparams, function(result) {
// you must render your view inside the callback
res.render('someview', {data: result});
});
// do not render here as you don't have the result yet.
}
If you have more than two external calls your code will looks like this:
exports.myController = function(req, res) {
longExternalCallOne(someparams, function(result1) {
longExternalCallTwo(someparams, function(result2) {
// you must render your view inside the most inner callback
data = {some combination of result1 and result2};
res.render('someview', {data: data });
});
// do not render here since you don't have result2 yet
});
// do not render here either as you don't have neither result1 nor result2 yet.
}
As you can see, once you have more than one long running async call things start to get tricky. The code above is just for illustration purposes. If your second callback depends on the first one then you need something like it, but if longExternalCallOne and longExternalTwo are independent of each other you should be using a library like async to help parallelize the requests https://github.com/caolan/async
You cannot stop your code. All you can do is check in all callbacks if everything is completed. If yes, go on with your code. If no, wait for the next callback and check again.
You should not stop your code, but rather render your view in your other resources callback, so you wait for your resource to be reached before rendering. That's the common pattern in node.js.
If you have to wait for several callbacks to be called, you can check manually each time one is called if the others have been called too (with simple bool for example), and call your render function if yes. Or you can use async or other cool libraries which will make the task easier. Promises (with the bluebird library) could be an option too.
I am guessing here, since there is no code example, but you might be running into something like this:
// let's say you have a function, you pass it an argument and callback
function myFunction(arg, callback) {
// now you do something asynchronous with the argument
doSomethingAsyncWithArg(arg, function() {
// now you've got your arg formatted or whatever, render result
res.render('someView', {arg: arg});
// now do the callback
callback();
// but you also have stuff here!
doSomethingElse();
});
});
So, after you render, your code keeps running. How to prevent it? return from there.
return callback();
Now your inner function will stop processing after it calls callback.

Possible to create many app.get calls with express.js through for loop?

this is my first post so thanks in advance for the help :)
I'm trying to make my main.js file and to make things easier I want to do something like this:
var pages = {
"/profile":{"page":"My Profile","loc":"./contentPages/profile"},
...
...
...
};
for (var item in pages) {
app.get(item, function(req, res){
if(req.session.user_id == null){
res.redirect('/');
return;
}
res.render(pages[item].loc, {
title:pages[item].page,
thisPage:pages[item].page
});
});
}
right now no matter what happens whatever I have last in the dictionary is the the page which is always rendered. Is there a way to do something like this or must I write out every page I want to create?
Thanks so much!
The problem is that all the closures created by function(req, res) refer to the same variable (item) so they all use whatever value it has when they're called rather than what it had when they were created, and that's going to be the last one.
Most straightforward workaround is to create the closures with a helper function:
function makeHandler(item) {
return function(req, res) {
// copy body of handler function here
};
}
and then replace the body of your loop with:
app.get(item, makeHandler(item));
Now each handler gets its own private copy of item which always retains the value it had when it was created.
You could also use an immediate function invocation to create the closures, but that would make the code look a little more cluttered.

Node-soap client and scope of the callback

I'm using the node-soap client from milewise (create API by the way), but I have some difficulties to get the results of the callback to the right scope.
Here is the code I have for now:
function generateSoapRequest(req, res, next)
{
soap.createClient('http://127.0.0.1:' + cfg.service_port + cfg.service_url_path,
function(err, client) {
client.CXIf.CXIf.CXProcessXML(
{"XMLRequestData": {"CXLogon": {"UserID":"1901007", "Password":"2580", "LogonType":11 } } },
function(err, result, body) {
if (err) {
console.log(err);
return;
}
console.log(result);
var cxresponse = result.XMLResponse[0].CXResponse;
console.log('SessionID:' + cxresponse.SessionID + ' SessionInstanceID:' + cxresponse.SessionInstanceID);
});
});
}
function getVoiceMailInformation(req, res, next) {
var cxresponse = generateSoapRequest(req, res, next);
var something = doSomethingNext(cxresponse);
}
function doSomethingNext(cxresponse){....; return something;}
Basically, when I launch the getVoiceMailInformation(), it creates a soap client and request some information through the generateSoapRequest().
The next step would be to get the result of that function (not implemented in the code above, because I don't know how) and do something else.
My problem is soap.createClient is asynchronous, so the callback is fired well after the function is complete.
What would be the best approach ?
(Maybe it's something trivial, but the scope of an anonymous function in javascript is something that is killing me.)
Any help will be very appreciated.
Basically you can't do something like:
var cxresponse = generateSoapRequest(req, res, next);
because the function you're calling invokes asynchronous code, and therefore can't return a value that's determined by that code. The normal way around this is to give the function an extra callback parameter for a function that will be called with the result once the result becomes available. It doesn't have to be an anonymous function; it can be a named function. In your case, (assuming you've modified generateSoapRequest to take a callback as its fourth argument and call it when the results are ready, you could write
generateSoapRequest(req, res, next, doSomethingNext);
and then doSomethingNext will be called with cxresponse as an argument. Of course, since doSomethingNext also gets called asynchronously, it can't return a value either, so you'll have to apply the same technique to it.
The async module can make this sort of thing easier: in particular, its "waterfall" pattern is useful when you have a bunch of functions that have to run in sequence, each being called back from the previous one.

Resources