I set up a Restify route using the following code. I create a pseudoclass, instantiate the object and use that as the handler. I want the object itself to be bound to "this" in the "ping" function so I have access to the member variables. However, "this" ends up pointing to some restify object that contains routes, etc. Is this something that just won't work with Restify?
var Handler1 = function() {
if (!(this instanceof Handler1 )) {
return new Handler1 ();
}
...
}
HttpHandlers.prototype.ping= function(req, res, next) {
//this doesn't point to the handler1 object.
return next();
}
...
var myhandler1 = new Handler();
app.get("/ping", myhandler1.ping , handler2);
handler1.ping.bind(myhandler1 )
I would try giving an object instance as the route instead of the object. That makes bit more sense to me.
class Pong1 {
constructor(name) {
this.name = name;
}
ping = res => res.write(`PONG ${this.name}`);
}
const pong1 = new Pong1('Pongy);
app.get('/ping', pong1.ping);
This is more like an ES2017 version, which I think is preferable. You should be able to convert to a more ES5 syntax if you really want.
It turns out that I needed to pass in the bound function:
app.get("/ping", myhandler1.ping.bind(myhandler1), handler2);
Related
why this code compiles
var Person = function() {
console.log("CALLED PERSON")};
Person.prototype.saySomething = function() {
console.log("saySomething PERSON")};
var ape = new Person();
ape.saySomething();
and this code throws error Cannot set property 'saySomething' of undefined
var Person = async function() {
console.log("CALLED PERSON")};
Person.prototype.saySomething = function() {
console.log("saySomething PERSON")};
var ape = new Person();
ape.saySomething();
When you use async function() {}, you are declaring an asynchronous function object. That's different than a regular function object. The asynchronous function object does not have a prototype.
So, when you try to do this:
var Person = async function() {
console.log("CALLED PERSON")
};
Person.prototype.saySomething = function() {
console.log("saySomething PERSON")
};
Person.prototype is undefined because there is no prototype on an asynchronous function object. Thus attempting to assign something to Person.prototype.saySomething causes the error you see because Person.prototype is undefined.
There is some logic to this because an asynchronous function can't be used as a constructor because an asynchronous function always returns a promise so it can't ever return a new object as in let obj = new f(). So, there's no purpose in having a .prototype property because it can't be used that way.
If you really wanted to asynchronously create an object, you could always create an async factory function that returns a promise that resolves with an object.
It is possible to add an async function in the end of the prototype chain.
Please notice that this works well in nodejs 8.11.1+.
// lets start with defining some cool async function who takes the time and
// awaits a promise
async function someCoolAsyncFunction() {
// this let will be returned after timeout in a different value.
let coolStuff = 'still boring';
// do something cool which takes time
await new Promise((resolve, reject) => setTimeout(() => {
coolStuff = 'an epiphany';
resolve();
}, 1000))
return coolStuff;
}
// Now let's define the 'regular' prototype chain with it's boring functions.
function Person(p) {
this.constructorPropery = p;
return this;
}
Person.prototype.notAsync = function() {
// do something regular in the prototype chain
console.log("Let's build some ",this.constructorPropery)
this.kindOfPerson = 'Regular and boring';
return this;
}
// And now, lets add an async function to this chain
Person.prototype.someAsyncFunction = async function() {
// you will still have access to 'this' in this function as long as the
// previous function in the prototype chain returnes 'this'
console.log('I used to be someone ',this.kindOfPerson);
// Now, this is our time to shine, lets await something cool
this.lifeChangingEvent = await someCoolAsyncFunction();
console.log('Until I had ',this.lifeChangingEvent);
a.kindOfPerson = 'enlightened';
console.log('and now I am ', a.kindOfPerson);
return this;
}
So this will work:
new Person('charachter').notAsync().someAsyncFunction();
But this WILL NOT work:
new Person('charachter').someAsyncFunction().notAsync();
And if you really need the data in 'this' outside the prototype chain you can also do:
let myself = new Person('charachter').notAsync();
console.log('myself.kindOfPerson is: ',myself.kindOfPerson);
myself.someAsyncFunction();
console.log('myself.kindOfPerson now is: ',myself.kindOfPerson);
Be sure to remember which prototype is an async function for which function or use your own naming convection for that.
I recently tried updating my project code structure with es6 classes in nodejs.
Here's what a controller class look like
class TaskController {
constructor(io, redisClient) {
this.socket = io;
this.redisClient = redisClient;
}
create(req, res) {
let taskDetails = req.body;
taskDetails.owner = req.user.id;
let errorFields = Validation.validate(taskDetails, [
{ name: 'title', type: 'text' }
]);
if (errorFields.length > 0) {
return ErrorHandler.handleError(res, errorFields);
}
...`
}
}
and Here's how I'm initializing the class in a routes file
module.exports = (app, io, redisClient) => {
let taskController = new TaskController(io, redisClient);
router.post('', middlewares.isAuthorized('task:create'), taskController.create);
app.use('/api/tasks', middlewares.isAuthenticated(), router);
};
The problem is while hitting the create api the this object is undefined in the create function.
With a little debugging, I know that the constructor is called when registering the routes.
But the taskController looses context when the create function is actually called.
How can I make it work with this structure or do I have to revert back to
module.exporting every function task controller?
You can use bind method to bind context. while passing create function.
router.post('', middlewares.isAuthorized('task:create'), taskController.create.bind(taskController));
create method is losing context because it is getting called in different scope by post method.
You can bind context using bind method which returns a function and pass that function to create method.
I'm trying to extend request in order to hijack and enhance its response and other 'body' params. In the end, I want to add some convenience methods for my API:
var myRequest = require('./myRequest');
myRequest.get(function(err, hijackedResponse, rows) {
console.log(hijackedResponse.metadata)
console.log(rows)
console.log(rows.first)
});
According to the Node docs on inherits, I thought I could make it work (and using the EventEmitter example in the docs works OK). I tried getting it to work using #Trott's suggestion but realized that for my use case it's probably not going to work:
// myRequest.js
var inherits = require('util').inherits;
var Request = require("request").Request;
function MyRequest(options) {
Request.call(this, options);
}
inherits(MyRequest, Request);
MyRequest.prototype.pet = function() {
console.log('purr')
}
module.exports = MyRequest;
I've been toying with extend as well, hoping that I could find a way to intercept request's onRequestResponse prototype method, but I'm drawing blanks:
var extend = require('extend'),
request = require("request")
function myResponse() {}
extend(myResponse, request)
// maybe some magic happens here?
module.exports = myResponse
Ended up with:
var extend = require('extend'),
Ok = require('objectkit').Ok
function MyResponse(response) {
var rows = Ok(response.body).getIfExists('rows');
extend(response, {
metadata: extend({}, response.body),
rows: rows
});
response.first = (function() {
return rows[0]
})();
response.last = (function() {
return rows[rows.length - 1] || rows[0]
})();
delete response.metadata.rows
return response;
}
module.exports = MyResponse
Keep in mind in this example, I cheated and wrote it all inside the .get() method. In my final wrapper module, I'm actually taking method as a parameter.
UPDATED to answer the edited question:
Here's a rough template for the contents of your myResponse.js. It only implements get(). But as a bare bones, this-is-how-this-sort-of-thing-can-be-done demo, I hope it gets you going.
var request = require('request');
var myRequest = {};
myRequest.get = function (callback) {
// hardcoding url for demo purposes only
// could easily get it as a function argument, config option, whatever...
request.get('http://www.google.com/', function (error, response, body) {
var rows = [];
// only checking error here but you might want to check the response code as well
if (!error) {
// mess with response here to add metadata. For example...
response.metadata = 'I am awesome';
// convert body to rows however you process that. I'm just hardcoding.
// maybe you'll use JSON.parse() or something.
rows = ['a', 'b', 'c'];
// You can add properties to the array if you want.
rows.first = 'I am first! a a a a';
}
// now fire the callback that the user sent you...
callback(error, response, rows);
});
};
module.exports = myRequest;
ORIGINAL answer:
Looking at the source code for the Request constructor, it requires an options object that in turn requires a uri property.
So you need to specify such an object as the second parameter in your call():
Request.call(this, {uri: 'http://localhost/'});
You likely don't want to hard code uri like that inside the constructor. You probably want the code to look something more like this:
function MyRequest(options) {
Request.call(this, options);
}
...
var myRequest = new MyRequest({uri: 'http://localhost/'});
For your code to work, you will also need to move util.inherits() above the declaration for MyRequest.prototype.pat(). It appears that util.inherits() clobbers any existing prototype methods of the first argument.
sir/madam exlain the flow of node.js from client to server with the dynamic parameters passing from userinterface to api's based up on these parameters we will get the output from api.for example sabre api etc..
exports.flightDestinations = function(req, res) {
var callback = function(error, data) {
if (error) {
// Your error handling here
console.log(error);
} else {
// Your success handling here
// console.log(JSON.parse(data));
res.send(JSON.parse(data));
}
};
sabre_dev_studio_flight.airports_top_destinations_lookup({
topdestinations: '50'
}, callback);
};
we want this value 50 from user...and how to give this value?and how to call this function in node.js.
The exports variable is initially set to that same object (i.e. it's a shorthand "alias"), so in the module code you would usually write something like this:
var myFunc1 = function() { ... };
var myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;
to export (or "expose") the internally scoped functions myFunc1 and myFunc2.
And in the calling code you would use:
var m = require('mymodule');
m.myFunc1();
where the last line shows how the result of require is (usually) just a plain object whose properties may be accessed.
NB: if you overwrite exports then it will no longer refer to module.exports. So if you wish to assign a new object (or a function reference) to exports then you should also assign that new object to module.exports
It's worth noting that the name added to the exports object does not have to be the same as the module's internally scoped name for the value that you're adding, so you could have:
var myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required
followed by:
var m = require('mymodule');
m.shortName(); // invokes module.myVeryLongInternalName
I am trying to wrap the node-memcached api with deferred's promisify in order to simplify my nested callbacks.
When I try to call the promisified function I just get "TypeError: Cannot read property 'namespace' of undefined".
Memcached = require('memcached');
var memcache = new Memcached('localhost:11211');
var add = deferred.promisify(memcache.add);
add('myKey', 'myVal', 0)(function(result) {
...
});
I can't seem to find anyone else trying to wrap node-memcached, or getting my same error. Any insight into what may be going wrong? Or maybe even a push into a better direction if this is imperfect?
Thanks!
EDIT::
Just wanted to response that I found the best solution I could for now by doing some digging.
It seems that deferred.promisify calls the passed function with its own scope (this), instead of the context of the function that is passed in.
Using my own promisfy function appears to fix the issue (idea from http://howtonode.org/promises):
function promisify(fn, context) {
return function() {
var def = deferred();
var args = Array.prototype.slice.call(arguments);
args.push(function(err, val) {
if (err !== null) {
return def.reject(new Error(err));
}
return def.resolve(val);
});
fn.apply(context, args);
return def.promise;
};
}
When promisify instances members you should bind it to this instance like:
Memcached = require('memcached');
var memcache = new Memcached('localhost:11211');
var add = deferred.promisify(memcache.add.bind( memcache ) );
add('myKey', 'myVal', 0)(function(result) {
...
});