express-restify-mongoose error propogation - node.js

I am having a problem serving up error messages using express-mongoose-restify.
My schema has a hook like
myschema.pre('save', function(next){
// If validation fails
next(new Error('failed to validate model'))
})
For error handling I have (something similar to) the following code
resify.serve(express.Router(), mongoose.model('myschema', {
onError: function(err, req,res,next){
console.log(err)
res.status(400).json(err)
}
})
The output to the console when validation fails is as follows:
{ [Error: failed to validate model] statusCode : 400 }
In my client I have the following (jquery) ajax error handler:
$( document ).ajaxError(function( event, jqxhr, settings, thrownError ) {
console.log(jqxhr)
console.log(thrownError)
});
thrownErorr is equal to "Bad Request" and jqxhr has reseponseText: "{"statusCode" : 400}" similar (but parsed to JS) for the responseJSON. The message failed to validate model is not being sent to the client. I think that I am misunderstanding the type of object that err is in my sever side error handler. Any thoughts? Thanks in advance!

This is one of those cases where writing the question made me think of the right question to ask myself in order to answer it.
The V8 error object that is use by node does not send the additional information such as the stack, message etc when converted to JSON. My problem was solved by reading up on the properties of the Error object here.
In particular using the following handler, the error is successfully relayed to the client
onError : function(err, req, res, next){
res.status(400).json({
message : err.message,
stack : err.stack
})
}

Related

NodejS : Error: Can't set headers after they are sent to the client

I am quite new to node and am currently encountering an error that seems pretty common: Error: Can't set headers after they are sent to the client.
I've read a few threads but cannot wrap my head around this one, here is my code so far:
router.get('/:id', (req, res) => User.findAll({
where : {
id: req.params.id,
},
attributes : {
exclude : ['updatedAt'],
}
})
.then(user => {
res.send(user);
res.sendStatus(200);
})
.catch((err) => console.log(err)));
What's wrong here? Any help and advices would be greatly appreciated!
The real reason behind this problem is that you are using both
res.send(user) and res.sendStatus(200).
The error says: Error: Can't set headers after they are sent to the client
You already send something to the client (in this case res.send(user)) and you can't send another thing now (in this case res.sendStatus(200)).
Once you do res.send, res.redirect, res.sendStatus, res.render, you should not do add any of these again.
You will get this problem if you are using more than one at the same time. Even if you have something like:
for(condition) {
res.send("1st");
}
res.send("2nd");
You should add return statements in front of them like:
for(condition) {
return res.send("1st");
}
return res.send("2nd");
Also as #Halil Akar said that 200 status is always returned with res.send. You can also use res.status(301).send(user) to send data and a status at the same time.
I hope it helps.

Lambda authorizer response using async/await in Node.js

I'm trying to create a lambda authorizer on aws using node.js async/await instead of callbacks but there is no information on how to create the HTTP response returned to API Gateway. For example, if i return this :
{
statusCode: 401
}
the API gateway doesn't seem to understand and return an error 403 to the client :
{
"statusCode": 403,
"error": "Forbidden",
"message": "No principalId set on the Response"
}
Does anyone knows how to do what is described here : https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html
but using async / await ?
Thanks in advance !
EDIT :
The way to return an error 401 is simply to throw an error like this :
throw new Error("Unauthorized")
And if the user is explicitly deny / allow, simply return the JSON policy.
To return a 401 error you simply need to throw an error with "Unauthorized" as message, like this :
throw new Error("Unauthorized")
And if the user is explicitly deny / allow, simply return the JSON policy like you would do with callbacks.
I think the accepted solution does not work (anymore). I tried it like this:
exports.authorize = async (event, context) => {
throw new Error("Unauthorized")
}
It works but in my logs I can see this error:
ERROR Invoke Error {"errorType":"Error","errorMessage":"Unauthorized","stack":["Error: Unauthorized"," at Runtime.exports.authorize [as handler] (/var/task/handler/auth.js:21:13)"," at processTicksAndRejections (internal/process/task_queues.js:97:5)"]}
From what I've read (some code samples would be helpful) it sounds like you're not calling the callback right or it's not called in the right place. You can use
callback("Some error message.");
to send back a response w/ a 401 status code. You can also change this by doing something like:
var response = {
statusCode: 401, /* some number */
body: "Oops!" /* some message */
};
callback(null, response);
I would check out this page for more information.

send error message back to browser in nodejs

I have a node API that is working fine when tested using postman.
But when I use this API in my angular project there occurs an error and browser don't get any response there it keep waiting for a response. When I go to console I see the error message.
How I can make that error message to be sent back to the browser with full stack trace
In general, you will need to catch that error, then populate http response object with it just the same as if you were sending successful response data back to the requestor.
Synchronous processing:
try {
// do my requested stuff
res.status(200).json({something:"returned"});
} catch(ex) {
res.status(500).json(ex);
};
Promises:
Promise.resolve()
.then(() => {
// do my requested stuff
// return my results stuff to the client
res.status(200).json({something:"returned"});
})
.catch((ex) => {
// return 500 error and exception data to the client
res.status(500).json(ex);
});
Also, as standard practice you should catch all errors, and at the very least, you should return a 500 to the browser res.status(500) so you don't leave it hanging when unexpected issues arise.
And, of course you can return html rather than json, and/or more info in the response.
Good luck.

How return custom errors in mongoose?

Having a mongoose model is it possible to add error handling directly to the model using .on('error) listener?
My goal is to add custom error messages to the incoming errors depending on their origin. Also I was thinking about changing error messages to make them more user friendly.
this.model.on('error', function(error) {
if (someCondition)
error = new ApolloError('Custom message', 'NOT_FOUND')
return error;
});
Basically, I want to to receive an error with a code NOT_FOUND and a custom message whenever mongoose throws an error that satisfies some condition. Any help would be appreciated.
I've came up with the following solution, which is to use toApolloError util found in apollo-server-errors
this.model.on('error', function(error) {
toApolloError(error, 'USER_INPUT_ERROR');
});

Express Error Handling - Get Status Code

If I define error handling middleware with express like so:
app.use(function(err,req,res,next){
// Do Stuff
});
How do I get the HTTP status code of the error(or do I just assume is's a 500)?
Thanks,
Ari
In short, your code has to decide the appropriate error code based on the specific error you are handling within your error handling middleware.
There is not necessarily an HTTP status code generated at this point. By convention, when I call next(error) from a middleware function or router handler function, I put a code property so my error handling middleware can do res.status(err.code || 500).render('error_page', error); or something along those lines. But it's up to you whether you want to use this approach for your common 404 errors or only 5XX server errors or whatever. Very few things in express itself or most middleware will provide an http status code when passing an error to the next callback.
For a concrete example, let's say someone tried to register a user account in my app with an email address that I found already registered in the database, I might do return next(new AlreadyRegistered()); where the AlreadyRegistered constructor function would put a this.code = 409; //Conflict property on the error instance so the error handling middleware would send that 409 status code. (Whether it's better to use error handling middleware vs just dealing with this during the normal routing chain for this "normal operating conditions" error is arguable in terms of design, but hopefully this example is illustrative nonetheless).
FYI I also recommend the httperrors npm module which provides nicely-named wrapper classes with a statusCode property. I have used this to good effect in a few projects.
You could try to define the status code in the route:
app.get('/force-error', function(req, res) {
res.status(400)
next(new Error('Bad Request.'))
})
Then:
server.use(function serverErrorHandler (err, req, res, next) {
const code = res.statusCode
// if status 200 change to 500, otherwise get the defined status code
res.status(code === 200 ? 500 : code)
// check if it's a ajax request
if (req.xhr)
res.json({
error: {
status: res.statusCode,
message: err.message,
stack: err.stack,
}
})
else
next(err)
})

Resources