Loopback beforeRemote for PUT requests - node.js

Using Loopback framework, I want to perform some operations before the Item is edited hence I am trying this but unable to bind this to the update hook.
Item.beforeRemote("update", function(ctx,myitem,next) {
console.log("inside update");
});
Instead of update I have tried with updateAttributes,updateById, create but none works. This kind of beforeRemote hook works well with create on POST, but unable to get it with PUT during edit.
The last solution left with me is again inspect the methodString with wildcard hook but I want to know if there is anything documented which I could not find.
Item.beforeRemote("**",function(ctx,instance,next){
console.log("inside update");
});

I know that two year have passed since this post was opened, but if any body have the same question and if you use the endpoint your_model/{id} the afterRemote hook is replaceById.
If you need to know which method is fired in remote hook use this code:
yourModel.beforeRemote('**', function(ctx, unused, next) {
console.info('Method name: ', ctx.method.name);
next();
});

Contrary to the comments, save is a remote hook, not an operation hook, but you want to use it as: prototype.save. The relevant operational hook would be before save. You can see a table of these on the LoopBack docs page. I would probably implement this as an operational hook though, and use the isNewInstance property on the context to only perform the action on update:
Item.observe('before save', function(ctx, next) {
if (ctx.isNewInstance) {
// do something with ctx.currentInstance
}
next();
});

Sorry for bumping into old question but its for those who are still searching.
'prototype.updateAttributes' can be used as remote hook for update requests.
and #jakerella , there is no remote hook called 'save' , i myself tried it, but didnt work.

Came here looking for another thing, guess it will be helpful to someone.
For before remote model/:id patch method you have to use "prototype.patchAttributes".

On loopback3 for PATCH you can use "prototype.patchAttributes" to sanitize your data before the update.
YourModel.beforeRemote('prototype.patchAttributes', (ctx, unused, next) => {
console.log(ctx.args.data);
next();
});

Related

Execute code on error

I want to execute a code of automated mail whenever there is any kind of error from any of the API.
Though this is possible to write that code in catch block of a remote method but my code base is too long and hence this is not a best fit.
Another issue with this is approach is for API which are not custom remote method and are generated by loopback, it is hard to use catch block with them.
Can someone help me with an easy approach where I need to write code once and the end result will be whenever there is an error in any of my API my code for mail runs automatically.
Got the answer after struggling for a day.
Loopback provides RemoteHook (afterRemoteError) for a model-method,
_modelName_.afterRemoteError( _methodName_, function( ctx, next) {
//...
next();
});
So whenever a particular method returns any error this block of code is executed.
Read more about remote hooks : https://loopback.io/doc/en/lb2/Remote-hooks.html
To make this block of code run every time any method returns error, we can use wildcards
_modelName_.afterRemoteError(** , function( ctx, next) {
//...
next();
});
Read more about wildcards here : https://loopback.io/doc/en/lb2/Remote-hooks.html#wildcards
You should take a look at Loopback https://github.com/strongloop/strong-error-handler
I also strongly suggest integrating a service like Rollbar.

Express GET route will not work with parameters

I am new to Express and Mongoose. I am currently working on my first project, that is not a tutorial, and I has run into a problem.
I have multiple routes, they are defined in the index.js like this:
app.use('/api/client',require('./routes/client'));
app.use('/api/host',require('./routes/host'));
In the routes, there are multiple verbs that work, like PUT and POST.
Here is the problematic route (I am trying to do more that what is presented here, but what is presented here, does not work as well):
router.get('/ama/:id', function (req, res, next) {
Ama.findById(req.params.id).then(function(Ama){
res.send(Ama);
});
});
This should work, right? It should return the document in the database, with that id. And I have checked if the document excists, probably around a 100 times.
Now, if I simplify the route greatly, removing the id, and make a simple response, the route works:
router.get('/ama', function (req, res, next) {
res.send({type:"GET"});
});
It's so wierd, that as soon as i add the parameter, i get a:
<pre>Cannot GET /api/host/ama</pre>
in Postman.
Any ideas? Mongod is running, my other routes are working.
It looks like you're trying to retrieve this URL:
/api/host/ama?id=SOMEID
However, you have a route declared for URL's that look like this:
/api/host/ama/SOMEID
In other words, the id is part of the path of the URL, and not passed as a query string parameter (that's what /:id means: it's a placeholder for a part of the URL that the route should match).
So either change the request-URL by adding the id to the path (/api/host/ama/58e395a8c6aaca2560089c‌​e7), or rewrite your route handler to something like this:
router.get('/ama', function (req, res, next) {
Ama.findById(req.query.id).then(function(Ama){
res.send(Ama);
});
});
However, I would advise using the former (making the id part of the URL).
There are two problems here:
router.get('/ama/:id', function (req, res, next) {
Ama.findById(req.params.id).then(function(Ama){
res.send(Ama);
})
res.send(req.params.id)*/
});
First of all, res.send(req.params.id) will run before the res.send(Ama); and it will probably send the entire response. You are missing the .exec() method call (see the answer by Cédric De Dycker for details). The res.send() can only be reliably used once. Maybe you want res.write() instead if you want to wrte multiple things. Also you don't handle the promise rejection so you don't handle database errors. To know why you should always handle the promise rejections see this answer: Should I refrain from handling Promise rejection asynchronously?
The parameter should work fine but it seems you missed to add .exec to your query
Ama.findById(req.params.id).exec().then(function(Ama){
res.send(Ama);
})

Loopback update model after save

I want to update last inserted/updated document(row) in "after save" hook without create new instance of that like this:
Model.observe('after save', function (ctx, next) {
ctx.someProperty = 'Foo';
ctx.update();
});
How it possible?
I'm not sure what you mean by 'update' a model. As far as I know, there is no update() function on the generic model class. If you're looking for updateAttribute then the documentation on that functionality is here.
However, assuming your question is just "How do I access the observed model inside of a loopback hook?" then the answer is that the instance is stored at ctx.instance rather that returned as ctx variable itself. See the examples here.
E.g.
Model.observe('after save', function (ctx, next) {
ctx.instance.updateAttributes({someProperty: 'Foo'})
});
If you can describe in more detail the functionality you're trying to achieve with the update() function, I will try to address that question. Note also that the code above would probably cause an infinite loop - because the updateAttribute call will itself trigger the 'after save' hook - which is another reason why I'm not so sure what you're really asking.

mongoose pre update not firing

I have follow the directions in mongoose here
PostSchema.pre('update', function() {
console.log('pre update');
console.log(this);
});
it is not firing this middleware. Am I missing something here?
I have added next so it looks exactly like my pre save, however that still does nothing.
Make sure you don't define this after mongoose.model() has been called. Please also take note that findOneAndUpdate / upserts or updates won't trigger this hook. Another reason why it wouldn't execute is that validation fails. Therefore you would need to setup a pre('validate') hoke
I think you have to add the await keyword before your promise.

Extending MongoDB's "save" method in nodejs

In our app, we have a large document that is the source of most of our data for our REST api.
In order to properly invalidate our client-side cache for the REST api, i want to keep track of any modifications made to teh document. The best we came up with is to extend the mongo save command for the document to send off the notification (and then save as usual).
The question is, how does one actually do this in practice? Is there a direct way to extend mongo's "save" method, or should we create a custom method (i.e. "saveAndNotify") on the model that we use instead (which i would avoid if i can)?
[edit]
So in principle, i am looking to do this, but am having an issue not clobbering the parent save function();
mySchema.methods.save = function() {
// notify some stuff
...
//call mongo save function
return this.super.save();
};
Monkey patching the core mongo object is a bad idea, however it turns out mogoose has a middleware concept that will handle this just fine:
var schema = new Schema(..);
schema.pre('save', function (next) {
// do stuff
next();
});

Resources