Access request headers from beforeSave Model Hook

陌路散爱 提交于 2019-12-01 16:53:37

问题


How can i access the details of the user who raise the request from a Model Hook

Comment.beforeSave =  function(next,com) {
//Want to add 2 more properties before saving 
com.added_at = new Date();    
com.added_by =  //How can i set the user id here ??
//In case of a Remote hook i have ctx in param and i can get user id like this     ctx.req.accessToken.userId;  But in Model Hook how can i do the same?    
next();    
};

Is there any way to do this? I tried with Remote hook for main Item in the way

MainItem.beforeRemote('**', function(ctx, user, next) {   
if(ctx.methodString == 'leave_request.prototype.__create__comments'){       
    ctx.req.body.added_by = ctx.req.accessToken.userId;     
    ctx.req.body.added_at = new Date();                         
    console.log("Added headers as .."+ctx.req.body.added_by);
}    
else{   
    ctx.req.body.requested_at = new Date();
    ctx.req.body.requested_by = ctx.req.accessToken.userId; 
    console.log("Added header @ else as .."+ctx.req.body.requested_by);
}
next();

});

And i get the console logs properly once i make request from explorer , but But the explorer always return me the error

"error": {
    "name": "ValidationError",
    "status": 422,
    "message": "The `comment` instance is not valid. Details: `added_by` can't be blank; `added_at` can't be blank.",
    "statusCode": 422,
    "details": {
      "context": "comment",
      "codes": {
        "added_by": [
          "presence"
        ],
        "added_at": [
          "presence"
        ]
      },
      "messages": {
        "added_by": [
          "can't be blank"
        ],
        "added_at": [
          "can't be blank"
        ]
      }
    },
    "stack": "ValidationError: The `comment` instance is not valid. Details: `added_by` can't be blank; `added_at` can't be blank.\n   "
  }
}

and my model is like

 "properties": {
"body": {
  "type": "string",
  "required": true
},
"added_by": {
  "type": "number",
  "required": true
},
"added_at": {
  "type": "date",
  "required": true
},
"leave_request_id":{
  "type": "number",
  "required": true
}

}


回答1:


It seems that you can't update related model with simply overriding ctx.req.body. Instead of you should override ctx.args.data - it looks like this ctx parameter is used to initalize the related model.

So it will look like that:

MainItem.beforeRemote('**', function(ctx, user, next) {   
  if(ctx.methodString == 'leave_request.prototype.__create__comments'){  
     ctx.args.data.added_by = ctx.req.accessToken.userId;     
     ctx.args.data.added_at = new Date();                         
     console.log("Added headers as .."+ctx.args.data.added_by);
  }    
  else{  ... }
  next();



回答2:


The beforeRemote hooks execute before the model hooks, so you can add the userId to the request body.

Comment.beforeRemote('**', function (ctx, unused, next) {
    var userId = ctx.req.accessToken.userId;
    if (ctx.methodString == 'Comment.create' || ctx.methodString == 'Comment.updateAttributes') {
        ctx.req.body.userId = userId;
    }
    next();
});

you might want to review which methodstring suit you best.




回答3:


Faced with the same problem, I used node expiremantal domain feature (that intended for error handling).

Saving incoming request object:

// -- Your pre-processing middleware here --
app.use(function (req, res, next) {
  // create per request domain instance
  var domain = require('domain').create();

  // save request to domain, to make it accessible everywhere
  domain.req = req;
  domain.run(next);
});

Next inside model hook you have access to req object, which is created per each connection:

process.domain.req 

Also StrongLoop team added context propagation (based on continuation-local-storage), but it is not documented yet.




回答4:


I solved this by adding the middleware for body parsing. In the middleware.js I wrote the following code:

...
"parse": {
   "body-parser#json": {},
   "body-parser#urlencoded": {"params": { "extended": true }}
},
...

Also, in the server.js I added the require for the body parser and multer:

var loopback = require('loopback');
...
var bodyParser = require('body-parser');
var multer = require('multer');
...

app.use(bodyParser.json()); // application/json
app.use(bodyParser.urlencoded({ extended: true })); // application/x-www-form-urlencoded
app.use(multer()); // multipart/form-data
...

Then add the dependencies in the package.json

"body-parser": "^1.12.4",
"multer": "^0.1.8"

Now you can do things like the following in the /models/user.js (for any model)

  user.beforeRemote('create', function(ctx, unused, next) {
     console.log("The registered user is: " + ctx.req.body.email);
     next();
  });

I hope this helps! :)




回答5:


If we assume that there is a relation comments of User -> Comment, you may also to try relation method POST /users/{user_id}/comments which will populate the foreignId (which can be added_by).

Another thing is added_at. As far as I understand, validation hook is triggered before create hook. It means that validation will fail, since this field is marked as required in a model. The question is whether this field should be marked as required, since it is set by the server, and not required to be set by the client of the API.



来源:https://stackoverflow.com/questions/26927791/access-request-headers-from-beforesave-model-hook

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!