How to add custom paramater in error object lb4? - node.js

I am using strongloop 4 (lb4). I am facing one issue that in error object I need to one more custom parameter in the error object.
I want it on the global level. On every error, I want to add that custom parameter in every error message.
In loopback4 global error handling is done by src/sequence.ts.
Suppose the error message object is.
{
"error": {
"statusCode": 400,
"name": "xyz",
"message": "firstName is required"
}
}
I want error object output like.
{
"error": {
"customParam" : "customParam",
"statusCode": 400,
"name": "xyz",
"message": "firstName is required"
}
}

Cross-posting the answer I gave on GitHub in https://github.com/strongloop/loopback-next/issues/1867#issuecomment-434247807
Building HTTP error responses is a tricky business. It's easy to get it wrong and open your application to attacks.
In LoopBack (both 3.x and 4.x), we use our strong-error-handler middleware to take care of this. See Handling Errors in our docs.
Here are the important security constraints to keep in mind:
In production mode, strong-error-handler omits details from error responses to prevent leaking sensitive information:
For 5xx errors, the output contains only the status code and the status name from the HTTP specification.
For 4xx errors, the output contains the full error message (error.message) and the contents of the details property (error.details) that ValidationError typically uses to provide machine-readable details about validation problems. It also includes error.code to allow a machine-readable error code to be passed through which could be used, for example, for translation.
In debug mode, strong-error-handler returns full error stack traces and internal details of any error objects to the client in the HTTP responses.
Now that I have warned you, LoopBack 4 makes it very easy to format the error messages your way. Just provide a custom implementation of the Sequence action reject. See Customizing Sequence Actions in our docs, it explain how to create a custom send action. The solution for reject is pretty much the same, you just need a different signature for the action function.
export class CustomRejectProvider implements Provider<Reject> {
// ...
action({request, response}: HandlerContext, error: Error) {
// handle the error and send back the error response
// "response" is an Express Response object
}
}
Caveat: some errors thrown by LB4 have only code set, these errors need a bit of pre-processing to decide what HTTP status code they should trigger. (For example, the error code ENTITY_NOT_FOUND should be mapped to the status code 404). The built-in reject action does not yet expose this pre-processing for consumption by custom reject actions. It's an oversight on our side, l created a new issue https://github.com/strongloop/loopback-next/issues/1942 to keep track of that.

I tried adding error object into new object.
let error = new Error();
error.name = 'Invalid_OTP_AttemptsError';
error.status = 422;
error.message = 'You’ve exceeded the maximum number of One-Time Password (OTP) attempts';
let data={...error};
data.retryCount=foundMb.retryCount
data.resendCount=foundMb.resendCount
return callback(null,data);

Related

Node.js When updating a document failed, is best to throw an exception or returning information?

I have an updateDocument method in a class for a service layer in a node.js, express, mongoose application. I'm wondering what is the best practice for handing cases where the update method didn't update a document, for example if the wrong id is passed in.
Version 1: If the update wasn't successful, return an object with success: false:
async updateDocument(id, updates) {
const output = await this.DocumentModel.updateOne({ _id: id }, updates);
let message = 'Something went wrong';
let success = false;
let updatedItem = null;
if (output.nModified) {
message = 'Successfully updated document.';
success = true;
updatedItem = await this.getDocument(id);
}
return { message, success, updatedItem};
}
Version 2: If the update wasn't successful, throw an error:
async updateDocument(id, updates) {
const output = await this.DocumentModel.updateOne({ _id: id }, updates);
let updatedItem;
if (output.nModified) {
updatedItem = await this.getDocument(id);
} else{
throw new Error("The document wasn't updated")
}
return updatedItem;
}
Do you always throw an exception when the input, such as a bad id, isn't correct? Or could you return information about the update being a success or not? As newbie node.js developer, I'm not sure I am grasping the full picture enough to recognize problems with either method.
There is no golden way, only principles that lead to robust and well-maintainable software.
Generally, you should use a try-catch-statement for all kinds of errors that are not in your control (connections, disk space, credentials, ...) . The errors should then be handled as soon as possible, but not before. The reason for this is that you often don't know, yet, how to handle an error in an appropriate manner at a lower layer.
For logical "errors" that you can expect (wrong input format, missing username, unknown options, ...), you should use an if-statement or a validation function and then throw an error, if anything is not as expected.
In your case, you should check, if the methods updateOne or getDocument can throw errors. If yes, you should wrap these functions with a try-catch-statement.
A few more tips:
Both versions of your code are good. But I would prefer version 2 because it is more concise.
If you are sure that there is always an output object, you can destruct the nModified property like this:
const { nModified } = await this.DocumentModel.updateOne({ _id: id }, updates);
If you use a negative if-statement, you can reduce the depth of indentation and you can use const variables:
if (!nModified) {
throw new Error("The document wasn't updated")
}
const updatedItem = await this.getDocument(id);
Now, you could also directly return this.getDocument(id) and don't need the variable updatedItem anymore.
You can finally handle your errors in your controller classes.
You can use custom error classes to be consistent in your error handling and error messages all over your app.
I hope this is at least a bit helpful.
References
These are some similar questions with good answers. But you need to take care because many code examples are not in modern JavaScript.
A general discussion about the pros and cons of Error-Handling vs.
if-else-statements is done here:
What is the advantage of using try {} catch {} versus if {} else {}
Error-Handling in Node.js is discussed here in this thread:
Node.js Best Practice Exception Handling
It seemed like there were a lot of different opinions on this and not one go-to method. Here's some information I found and what I ended up doing.
When to throw an exception?
Every function asks a question. If the input it is given makes that question a fallacy, then throw an exception. This line is harder to draw with functions that return void, but the bottom line is: if the function's assumptions about its inputs are violated, it should throw an exception instead of returning normally.
Should a retrieval method return 'null' or throw an exception when it can't produce the return value?
Answer 1:
Whatever you do, make sure you document it. I think this point is more important than exactly which approach is "best".
Answer 2:
If you are always expecting to find a value then throw the exception if it is missing. The exception would mean that there was a problem.
If the value can be missing or present and both are valid for the application logic then return a null.
More important: What do you do other places in the code? Consistency is important.
Where should exceptions be handled?
Answer 1: in the layer of code that can actually do something about the error
Exceptions should be handled in the layer of code that can actually do something about the error.
The "log and rethrow" pattern is often considered an antipattern (for exactly the reason you mentioned, leads to a lot of duplicate code and doesn't really help you do anything practical.)
The point of an exception is that it is "not expected". If the layer of code you are working in can't do something reasonable to continue successful processing when the error happens, just let it bubble up.
If the layer of code you are working in can do something to continue when the error happens, that is the spot to handle the error. (And returning a "failed" http response code counts as a way to "continue processing". You are saving the program from crashing.)
-source: softwareengineering.stackexchange
Answer 2: Handle errors centrally, not within a middleware
Without one dedicated object for error handling, greater are the chances of important errors hiding under the radar due to improper handling. The error handler object is responsible for making the error visible, for example by writing to a well-formatted logger, sending events to some monitoring product like Sentry, Rollbar, or Raygun. Most web frameworks, like Express, provide an error handling middleware mechanism. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. Express, KOA) who is responsible for catching errors -> a centralized error handler is called -> the middleware is being told whether this error is an untrusted error (not operational) so it can restart the app gracefully. Note that it’s a common, yet wrong, practice to handle errors within Express middleware – doing so will not cover errors that are thrown in non-web interfaces.
-source; Handle errors centrally, not within a middleware
More: Best Practice Node.js: Error Handling
So it seems like these two principles disagree. #1 says to handle it right away if you can. So for me it would be in the service layer. But the #2 says handle it centrally, like in the server file. I went with #2.
My decision: throw the error in a custom error class
It combined a few methods people suggested. I am throwing the error, but I'm not "log and rethrow"-ing, as the answer above warned against. Instead, I put the error in a custom error with more information and throw that. It is logged and handled centrally.
So first in my service layer this is how an error is thrown:
async addUser(user) {
let newUser;
try {
newUser = await this.UserModel.create(user);
} catch (err) {
throw new ApplicationError( // custom error
{
user, // params that are useful
err, //original error
},
`Unable to create user: ${err.name}: ${err.message}` // error message
);
}
return newUser;
}
ApplicationError is a custom error class that takes an info object and a message. I got this idea from here:
In this pattern, we would start our application with an ApplicationError class this way we know all errors in our applications that we explicitly throw are going to inherit from it. So we would start off with the following error classes:
-source: smashingmagazine
You could put other helpful information in your custom error class, even maybe what EJS template to use! So you could really handle the error creatively depending on how you structure your custom error class. I don't know if that's "normal", maybe it's not SOLID to include the EJS template, but I think it's an interesting concept to explore. You could think about other ways that might be more SOLID to dynamically react to errors.
This is the handleError file for now, but I will probably change it up to work with the custom error to create a more informative page. :
const logger = require("./logger");
module.exports = (err, req, res, next) => {
if (res.headersSent) {
return next(err);
}
logger.log("Error:", err);
return res.status(500).render("500", {
title: "500",
});
};
Then I add that function to my server file as the last middleware:
app.use(handleError);
In conclusion, it seems like there's a bit of disagreement on how to handle errors though it seems more people think you should throw the error and probably handle it centrally. Find a way that works for you, be consistent, and document it.

What is considered standard when dealing with database errors in a REST application?

I'm currently writing a public REST service in Node.js that interfaces with a Postgres-database (using Sequelize) and a Redis cache instance.
I'm now looking into error handling and how to send informative and verbose error messages if something would happen with a request.
It struck me that I'm not quite sure how to handle internal server errors. What would be the appropriate way of dealing with this? Consider the following scenario:
I'm sending a post-request to an endpoint which in turn inserts the content to the database. However, something went wrong during this process (validation, connection issue, whatever). An error is thrown by the Sequelize-driver and I catch it.
I would argue that it is quite sensitive information (even if I remove the stack trace) and I'm not comfortable with exposing references of internal concepts (table-names, functions, etc.) to the client. I'd like to have a custom error for these scenarios that briefly describes the problem without giving away too detailed information.
Is the only way to approach this by mapping every "possible" error in the Sequelize-driver to a generic one and send that back to the client? Or how would you approach this?
Thanks in advance.
Errors are always caused by something. You should identify and intercept these causes before doing your database operation. Only cases that you think you've prepared for should reach the database operation.
If an unexpected error occurs, you should not send an informative error message for security reasons. Just send a generic error for unexpected cases.
Your code will look somewhat like this:
async databaseInsert(req, res) {
try {
if (typeof req.body.name !== 'string') {
res.status(400).send('Required field "name" was missing or malformed.')
return
}
if (problemCase2) {
res.status(400).send('Error message 2')
return
}
...
result = await ... // database operation
res.status(200).send(result)
} catch (e) {
res.status(500).send(debugging ? e : 'Unexpected error')
}
}

Socket.io error passing conventions

Background: In Node, it is common to pass an error object to a callback function in async calls as well explained in Error handling in Node.js by Joyent. A standard error object contains a name, a message, a stack trace and possible additional properties. Passing or throwing strings or plain objects as errors is considered a bad practice. With Socket.io, data can be transmitted from client to server and vice versa by emitting events and having an optional response callback. This opens up multiple ways to pass and handle errors.
Question: If a socket.io event from a client causes an error on the server, what is the best practice to inform the client about this? A plain error object in response? A separate error event and listener? How the error should be structured? Is there any best practices like is the case with Node? What are you using?
Example: Imagine socket.io used for login. A client logs in by emitting a username and a password like below:
socket.emit('login', {user: 'Foo', pass: 'Bar'}, function (response) {
...
});
On a successful login, the response contains a session token. But what if the username or the password do not match? Several approaches come to mind:
Approach 1 - plain error object: The response could contain a property error having a plain error-like object as its value, with standard name and message properties and possible additional ones:
{
error: {
name: 'InvalidUsernameOrPasswordError',
message: 'Username or password was invalid.',
usernameExists: false
}
}
The client thus tests if response contains an error and if not, continues with the login procedure:
socket.emit('login', {user: 'Foo', pass: 'Bar'}, function (response) {
if (response.hasOwnProperty('error')) {
// handle error
}
// do something with response.token
});
Approach 2 - simple string: Similar to Approach 1, but the error property is just a plain string representing the name of the error.
{
error: 'InvalidUsernameOrPasswordError'
}
This approach is light and sufficient in this naïve example but lacks ability to pass additional data about the error.
Approach 3 - separate event: The server could emit and the client listen additional events to handle possible outcomes:
socket.on('loginError', function (error) {
// handle error based on error.name and error.message
});
socket.on('loginSuccess', function (data) {
// handle successful login with data.token
});
socket.emit('login', {user: 'Foo', pass: 'Bar'});
This approach feels the most explicit and pure under the event emitting paradigm but requires multiple event handlers.
Conclusions: There seem to be many possible ways to pass and handle errors. Any experiences, thoughts or feels?
It depends on your "clients". If you have end users like people using an application they really don't care so much about how you send the error. At the end you are going to have a text on the frontend saying they are wrong. So you are the one who have to select which way you prefer for implementing the error handling on the backend.
If your clients are not end users like the case above, imaging you are creating an application or library and you have to say there was an error. You should return as much as information you can in order for people who use your application identify where you error is.
So at the end:
-For customers: You will show your errors on the frontend so that ups to you how you want manage the error.
-For developers: You should show as many error information as you can. Showing the stack trace, error code...

Handling errors at a global level

I am trying to understand how to build my error handling system for my api.
Let's say I have a the following line in a controller method :
var age = json.info.age;
with
json = {"id":1, "name":"John", info": {"age":27, "sex":"m"}}
Let's say that the object doesn't contain an info field, I'll get the following error TypeError: Cannot read property 'info' of undefined and my server will crash.
Is there a way to make a higher level abstraction and catch all the potential errors that I could have? Or should I have a try/catch system for each of the methods of my controllers?
BEWARE OF THE CODE BELOW, IT WILL BITE YOU WHENEVER IT CAN!
Don't use the code snippet below if you do not understand its
implications, please read the whole answer.
You can use the node way for uncaught errors. Add this in your config/bootstrap.js
Updated the snippet below to add what was said in the comments, also added a warning about using a global to respond to the user.
process.on('uncaughtException', function (err) {
// Handle your errors here
// global.__current__ is added via middleware
// Be aware that this is a bad practice,
// global.__current__ being a global, can change
// without advice, so you might end responding with
// serverError() to a different request than the one
// that originated the error if this one happened async
global.__current__.res.serverError();
})
Now, can doesn't mean should. It really depends on your needs, but do not try to catch BUGS in your code, try to catch at a controller level the issues that might not happen every time but are somehow expected, like a third-party service that responded with empty data, you should handle that in your controller. The uncaughtException is mainly for logging purposes, its better to let your app crash if there is a bug. Or you can do something more complicated (that might be better IMHO), which is to stop receiving requests, respond to the error 500 (or a custom one) to user that requested the faulty endpoint, and try to complete the other requests that do not relate to that controller, then log and shutdown the server. You will need several instances of sails running to avoid zero downtime, but that is material for another question. What you asked is how to get uncaught exceptions at a higher lvl than the controllers.
I suggest you read the node guide for error handling
Also read about domains, even thought they are deprecated you can use them, but you would have to deal with them per controller action, since sails does not provide any help with that.
I hope it helps.
You can check this way if you want to:
if (object != null && object.response != null && object.response.docs != null){
//Do your stuff here with your document
}
I don't really get what is your "object" variable in the first place, so i don't know if you can check it at a different level, is it a sails parameter to your controller ?
So that's how I did it, thanks to Zagen's answer.
module.exports.bootstrap = function(cb) {
process.on('uncaughtException', function (err) {
//Handle your errors here
logger.fatal(err);
global.__current__.res.serverError();
})
cb();
};
I send a generic error 500 to the user if any uncaught exception is thrown, and I log the error to the fatal level. On that way, my server is still accessible 24/7 and I can monitor the logs at another level and trigger an alarm on a fatal error. I can then fix the exception that was thrown.

how to log js errors at server

I wanted to know does YUI3 provides any way to try and catch errors functionality, where in after the error is captured we can show some customized error alert and simultaneously log the error at server side with the error exceptions and other details.
Also if this functionality is not there in yui3 then which all frameworks do one need to use to do this and which all are compatible with YUI.
I'm not aware of YUI3 providing exactly what you're after out-of-the box.
You can split your question into two parts:
Capturing errors
You either wrap your code with try/catch blocks or use a global error handler. It looks like YUI3 doesn't yet directly handle this (http://yuilibrary.com/projects/yui3/ticket/2528067) but handling it shouldn't be too hard, you'll just have to test for browser differences.
Sending Error data to the server
You ought to be able to use Y.IO to send back the error data to the server. It looks like you get errorMsg, url, lineNumber given to you, so you can just send them back to the server:
YUI().use("io-base",function(Y){
window.onerror = function(errorMsg, url, lineNumber){
Y.io("/errorHandler.php", {
data: {
errorMsg: errorMsg,
url: url,
lineNumber: lineNumber
}
});
alert("Sorry, something bad happened");
};
console.log("handler registered");
//now trigger an error
a.b.c="banana";
});
That seems to work here: http://jsfiddle.net/J83LW/
I'l leave the customized alert to you, I've left an alert here as a basic example of handling this

Resources