When I create a controller in sails.js with some standard method redefined, how do I call default parent method of this controller?
module.exports = {
create: function(req, res) {
//test some parameters
if (condition) {
//call regular super method, proceed as usual
//_super(); <- how to do this?
} else {
//do some other things
}
}
};
Update: for Sails >= v0.10.x, see the comment below from #naor-biton
If you want to access the default implementation (the blueprint), as of v0.9.3, you can call next() (the third argument to your controller). This is because Sails is based on the Express/Connect concept of middleware, allowing you to chain things together.
Please note that this behavior may change in a subsequent version, since next() is also how you call your default 404 handler (config/404.js) for actions which don't have a blueprint underneath them.
A better approach, if you're interested in using the blueprints but running a bit of logic beforehand, is to leave the controller action undefined and use one or more policies, which will be run beforehand.
Related
I'm requesting the blueprint route User.findOne in SailsJs on the basis of user Id but it itself is calling User.update. Also, I just experienced a new thing that on sending multiple parameters to findOne, it updates the record on the basis of any single matched parameter. On the other hand, If i do create a controller named user.findOne and call the same route via controller, it works perfectly fine.
Is that the right behavior by SailsJs or I'm doing some mistake anywhere?
I have the same issue, still wondering why is this happening,
I even tried creating an update function in my controller with some sample code but when I try hitting findOne from postman, it redirects me to my created update function.
Waiting for an answer on this serious issue.
However I found a solution by trying something like this (i.e. creating custom findOne function in the controller) and it worked:
findOne : function (req,res){
var myReq = req.params.all();
console.log(myReq);
User.findOne(myReq, function UserFound(err, user){
if (err) return res.negotiate("User not found!");
else{
console.log("I am getting here");
console.log(user);
return res.status(200).send(user);
}
})
}
Reworded:
A common pattern is to pass callback functions, such as with Mongoose's save (just for example and simplified - no error handling):
someMethod(req:Request, res:Response){
document.save( function(err){ res.status(200).send({message: 'all good'})});
}
I'd like to externalize the callback. You can do this this way:
var respond = function(err:any, res:Response){
res.status(200).send({message: 'all good'});
}
someMethod(req:Request, res:Response){
document.save( function(err){ respond(err, res)});
}
...but ideally I'd like to do this by just passing a function like respond without having to create a call back function to enclose respond. I wanted to know if this is possible. Since the anonymous function has access to res, I thought there might be some way to gain access to res in a function defined externally. It appears there is not a way to do this so I'll live with wrapping it.
My original question was trying to isolate the specific issue I was interested in - which is to gain access to the caller's variables implicitly. Doesn't seem like that is possible. Fair enough.
Original Question:
I'd like to externalize a bit of code I use frequently and I'm having trouble understanding closure in the context of a Typescript method. Take a look:
var test = function(){
console.log("Testing external: "+JSON.stringify(this.req.body));
}
class Handler {
static post(req: Request, res: Response){
(function(){
console.log("TESTING anon: "+JSON.stringify(req.body));
}) ();
test();
}
}
Besides the fact that this does nothing useful, in this bit of code, the inline anonymous function has access to the req object, but the test() function does not. this in test is undefined. Removing this to match the inline function doesn't help.
I believe if I were to bind on this for the call I'd just end up with a reference to the Handler class when I really want to bind on the post method.
My motivation for doing this is that I want to make a function that can be passed as a callback to a bunch of different request handlers. When I write the functions inline it all works, but when I externalize it I can't get a closure over the variables in the enclosing method. I've read "You Don't Know JS: this & Object Prototypes", and in pure Javascript I can manage to make these sorts of things work but I'm obviously doing something wrong here (it may not be Typescript related, maybe I'm just messing it up).
So bottomline - is there a way I can externalize the handler and get access to the method variables as if I were writing it inline? I could just create an inline anonymous function as the callback that calls the external function with all the variables I need, but I want to really understand what is happening here.
This is not an answer, but will hopefully give me enough feedback to give you one because its not at all clear what you're actually trying to accomplish here and whether or not you actually understand what the terms mean is an open question since you use them correctly one minute and sketchily the next.
var test = function(){
console.log("Testing external: " + JSON.stringify(this.req.body));
}
In strict mode this will throw an error, in sloppy it will try to access the req property of the global object which is not likely what you want.
(function(){
console.log("TESTING anon: "+JSON.stringify(req.body));
}) ();
The IFFE wrapper is completely unnecessary, it literally adds nothing to the party. So why include it?
static post(req: Request, res: Response){
console.log("TESTING anon: "+JSON.stringify(req.body));
test(); // is this the spot where you are 'in-lining?'
}
What I think you want is this:
var test = function(reqBody) {
console.log("Testing external: " + JSON.stringify(reqBody));
};
class Handler {
static post(req: Request, res: Response) {
test(req.body);
}
}
In express.js when we call
app.get(function(req,res){...}),
the function automatically receives request and response objects and we can give any name to function parameters like req,res or re,rs and many others.
I want to create a function that will rest in an object.
When I want to use this function it must receive default arguments which may be e.g simple int 4,3 and I must be able to specify parameter names as per my choice.And these arguments must be assigned to parameter names I have defined and I must be able to use those name in code inside function.
How can I achieve this?
You can write your own middleware for this. For example this is how I control the mandatory fields in requests :
router.post('/relations', controlBodyMiddleware(['userIdReceiver']), relation.create);
While you can have method like this :
controlQueryMiddleware(fields) {
return function(req, res, next){
if (!req.body.mandatoryField || req.body.mandatoryField !== 5){
return next(new Error('I want mandatoryField equal to 5'));
}
req.body.myFieldAccessibleInNextMiddleware = 'Yes, this would be there';
next();
};
}
I have found the solution myself.
It was all related to call back functions and passing the function definition to another function.
var app={
get:function(callback){
callback('Request object..','Response object..');
}
};
app.get(function(rq,rs){
console.log(rq,rs);
});
Here we can pass function definition in get method with parameters of your own choice that's what I wanted to know.
It is not necessarily express object or methods.
app can be any object and get can be any method of app.
With of course parameters not necessarily req and res objects.
I have a simple function which routes a HTTP query pattern, queries redis and sends a response. The following is the code
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname,function(err,obj){
console.log("the response from redis is ",obj)
cache.put(eventname,obj);
console.log("inserting to cache");
this.res.end(obj); // this object is root cause for all problems
});
}
The router object afaik, sends the response using this.res.end(obj) . I guess since I am trying to do this inside my redis client , I am getting error. Is there any other way to send the value as a response ? I thought of using emitter based model where the channel emits the response and listener gets it. but it feels like a round about way to solving this problem. Is there any simpler approach ?
The error may be because, where you're trying to use this, it doesn't have the intended value -- an object with a res property that in turn has an end() method.
That would be because every function in JavaScript has its own this with its own value. And, when nesting functions, using this will return the value for the closest function (i.e. shadowing).
To resolve that, you can save the intended value to a local variable:
router.get('/getinfo/:teamname', function main(teamname) {
var request = this;
rclient.hgetall(teamname,function(err,obj){
// ...
request.res.end(obj);
});
});
Or, bind the anonymous callback so both functions are forced to have the same this value:
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname, function(err,obj){
// ...
this.res.end(obj);
}.bind(this));
});
I'm very new to Node.js and I'm just trying to make sense of how the parameters work in the callback methods of the code.
I can only understand the first one, function(req,res), because I've used that in Java when working server-side, but I don't really understand how it automatically calls the memcached function or how that kicks off the rest, etc. If somebody could explain to me how this works I'd really appreciate it. Thank you
server.on('request', function(req, res) {
//get session information from memcached
memcached.getSession(req, function(session) {
//get information from db
db.get(session.user, function(userData) {
//some other web service call
ws.get(req, function(wsData) {
//render page
page = pageRender(req, session, userData, wsData);
//output the response
res.write(page);
});
});
});
});
It could roughly be compared to passing the anonymous class in Java. For example to sort a collection in Java you pass a comparator class which has a method for comparing two objects. Later, when sorting algorithms needs to compare the objects it calls the function in provided class.
In javascript functions are first class objects, which means we don't need a "wrapper" class and can pass it as a parameter to another function.
In your case "memcached.getSession" will execute is't logic, find the session, and calls the anonymous function you pass in the second parameter, with the session as parameter.