Consider the following hook:
User.afterRemote('**', function(ctx, result, next) {
delete result.password;
result.newProp = 'new-value';
result.email = 'modified:' + result.email;
next();
});
// Result of POST /users
{
password: '$2a$10$6Ck1zg3NgKLrsRHelaV9MuwwbOFbfxVnSccTcWvODRAC16c85/r0i',
email: 'modified:[email protected]',
credentials: [],
challenges: [],
id: 1
}
In other words, password property was not removed, newProp was not added, only the modification of an existing property was applied.
Partial workaround based on the internal details of ModelBaseClass:
user.afterRemote('**', function(ctx, result, next) {
delete result.__data.password;
result.__data.newProp = 'new-value';
result.email = 'modified:' + result.email;
next();
});
// Result of POST /users
{
password: null,
email: 'modified:[email protected]',
credentials: [],
challenges: [],
id: 1,
newProp: 'new-value'
}
Related and/or affected issues: #160, #161.
/cc @raymond @ritchie
I was contemplating two different approaches how to fix this.
ModelBaseClass.toObject() to include all own enumerable properties in the result.SharedMethod.toResult to perform a structured clone (*) of all return values when composing the final result object. This way the "after" callback will work with plain data objects instead of full Models, which makes it easier to add/delete/modify data. On the other hand, such solution will not allow "after" callback to call any methods on the result objects (e.g. in order to fetch more data from the DB and add it to the response).(*) The term "structured clone" comes from HML5 spec and is implemented e.g. by lodash.cloneDeep. Our implementation would have to modify the algorithm to clone only public properties (#160).
@raymondfeng @ritch Is there a reason why ModelBaseClass.toObject() enumerates only properties defined in the model schema and (optionally) in __data? The consequences of 2. are huge and I am not entirely sure if 2. is a good idea at all...
I ran into the same issue before. The data source juggler use __data as the internal representation of the property values and control the access through getter/setter functions. If you see a property on the instance directly, for example,
myObject.x = 'x';
if x is a predefined property for the model, the setter will add it to __data. Otherwise, it won't be intercepted.
IMO, for models with strict !== true, the owner properties should be copied during toObject().
Cross-posting from loopback-datasource-juggler#67.
There are two kinds of extra data that a developer may want to add:
AccessToken.user. There should be a way how to tell the AccessToken instance that it should include the cached value of "user" relation in the JSON.js
// inside User.login
accessToken.user(user);
if (include === 'user') {
accessToken.user.public = true; // made up API
accessToken.toJSON().user === user.toJson(); // true
js
model.set('foo', 'bar');
model.foo === 'bar'; // true
model.toJson().foo === 'bar'; // true
Fixed by the PR above.
It seems "delete result.field" still not affect the final response?
AFAIK, you need to call result.unsetAttribute('field') for that.
Thx for the tip, hope it can be put on the remote hook doc.
Thx for the tip, hope it can be put on the remote hook doc.
/cc @crandmck
I have a remote hook as follows -
Model.afterRemote ('**', function (ctx, result, next){
console.log ('afterRemote hook called.');
next ();
});
This hook gets called when GET is invoked from /explorer. However when a Model.find ({}) is executed from unit test case, the above hook is not getting called.
Any inputs on why remote hooks are not getting called when find is executed in unit tests?
Have this problem on remote hook intercepting a relationship get called.
Band.afterRemote('**.__get__proposals',function(ctx,inst,next) {
//i.e. inst = {};
inst.concert(function(err, concert){
inst = {concert : concert};
console.log(concert);//outputs the concert object correctly
next(null,inst);//the same with next();
}
});
}
when I'm getting this relationship I have the {} json as response object when I'm expecting {concert:concert}
it works after replacing the result in the context
ctx.result = {concert:concert};
before the next(); to be called
Just found out this old issue and definetely :+1: to @ulion : the unsetAttribute method should go in the doc regarding afterRemote hook
Just found out this old issue and definetely 馃憤 to @ulion : the unsetAttribute method should go in the doc regarding afterRemote hook
@kartsims would you like to contribute that improvement yourself? Here are the instructions to get you started: http://loopback.io/doc/en/contrib/doc-contrib.html
Most helpful comment
AFAIK, you need to call
result.unsetAttribute('field')for that.