sequelize handling rejection in the create statement - catch not firing - node.js

The sequelize create statement has an error and I would like to handle that error. Since the create statement has the error I need to handle promise rejection. How do I do that in code? Tried to look at the sequelize documents but unable to work it out.
db.Employee.create(empData,
{
include:[
{
model: db.EmployeeDetails
}
]
}).then(function(newEmployee){
res.json(newEmployee);
}).catch(function(err){
return next(err);
});
The error is on the create and so the webpage just gives an internal server error. I was under the impression that the catch was something that handled the promise rejection and failure. In this case, how can I handle the promise rejection in code. An example would be greatly appreciated.

By doing next(err), by default, you send a 500 Internal Server Error message. If you use Express, and want to show a custom error, just append a status code which is not 5xx to the error:
General Usage:
const err = new Error("my custom error")
err.statusCode = 400
next(err)
In your snippet, do:
db.Employee.create(empData, {
include:[
{
model: db.EmployeeDetails
}
]
}).then(function(newEmployee){
res.json(newEmployee);
}).catch(function(err){
err.statusCode = 400
next(err);
});
If you haven't set your error handler in Express you will need to add somewhere at the end of the main file this:
// Error Handler
app.use(function(err, req, res, next) {
console.error(err)
if (!err.statusCode) err.statusCode = 500;
let msg = err.message
// Do not expose 500 error messages in production, to the client
if (process.env.NODE_ENV === "production" && err.statusCode === 500) {
msg = "Internal Server Error"
}
res.status(err.statusCode).send(msg)
})

Your webpage showing a 500 error means the issue was caught / working as intended. What you need to do is figure out how to handle displaying that error in a pretty format - this being a UI task. If you want a 'patch' for hiding the issue, change your return to a res. This will trick your browser with a 200 status and hide the error.
I do want to add, I recommend trying async/await for sequelize. There's a good amount of usage examples with it.
Promise
db.Employee.create(empData,
{
include:[
{
model: db.EmployeeDetails
}
]
}).then(function(newEmployee){
res.json(newEmployee);
}).catch(function(err){
// Temporary patch
res.json("pretty error message");
});
Async/Await version
async function createEmployee(empData) {
try {
return await db.Employee.create(empData, {
include:[ { model: db.EmployeeDetails } ]
});
} catch (err) {
// Handle error here
return err;
}
}

Related

How to send a custom status and error message if no data found using Node.JS/express and axios?

If no user is found (it's just an example to understand error handling), I want to send a custom message such as
res.status(404).send('no user');
my client never receives that and instead I get:
[AxiosError: Request failed with status code 404]
What am I doing wrong? I cannot find any other solution and have been researching for a while now. Also wonder how I could send a custom status (if no data found it's 404 but what if I want to send 200)?
node express
router.get('/getuser', async (req, res) => {
try {
const user = await User.findOne({_id: req.user._id});
if (!user) {
res.status(404).send('no user');
} else {
res.status(200).send(user)
}
} catch(error) {
res.status(500).send(error)
}
});
frontend
const trycatch = async () => {
try {
const response = await axios.get(example.com/trycatch)
return response.data;
} catch (error) {
console.log(error)
}
}
Responses with a status code of 400 or more are treated as errors by axios. As a consumer, you can only react to that in the catch (error) clause, for example:
catch (error) {
switch (error.response.status) {
case 404: return "no user"; break;
default: return error.response.data;
}
}
But you can influence which statuses cause errors with the validateStatus option of the axios request.
Summary: Either you distribute your code between the try and the catch block, where the try block code handles successes (status < 400) and the catch block handles errors (status ≥ 400). Or you use validateStatus to change what counts as a success and what counts as an error.

How to auto send error of try catch block to Sentry in Node JS

I am building a Node JS application. I am using Sentry, https://docs.sentry.io/platforms/node/ in my application to monitor and report errors. But I am having a problem with global reporting for try catch block.
For example, I have a code block as follow.
const getUser = async (id) => {
try {
//do the database operation and return user
} catch (e) {
return {
data: null,
message: e.message
}
}
}
As you can see in the code, I am catching the error in the Try catch block. If I want to report the error to Sentry, I have to put in the following line in the catch block.
Sentry.captureException(e);
Basically, I am explicitly reporting the error. Is there a way to globally and automatically catch the error within the catch block and report it to the sentry. For, example, something like in PHP or Laravel. We will just have to initialize and configure the Sentry in one centralized place of the application and app will report any errors to the Sentry.
Sentry starts monitoring the whole application just by adding, the init function, somewhere in a global scope.
For example :
Sentry.init({
debug: appConfig.env === 'staging',
dsn: appConfig.sentryDSN,
environment: appConfig.env,
integrations: [new Integrations.BrowserTracing()],
release: [pjson.name, pjson.version].join('#'),
tracesSampleRate: 1.0,
ignoreErrors: [],
normalizeDepth: 10, // Or however deep you want your state context to be.
// (breadcrumb: Breadcrumb, hint?: BreadcrumbHint | undefined) => Breadcrumb | null
beforeBreadcrumb(breadcrumb: Sentry.Breadcrumb, hint: Sentry.BreadcrumbHint | undefined) {
return breadcrumb.category === 'xhr' ? breadcrumb : null;
},
});
You can stay just to that 'conf/init' if you like, this captures some errors, which are: `every error that inherits from the 'Error' object, like: TypeError, RangeError, ReferenceError, SyntaxError, etc , for more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
But its better to handle the errors explicitly, and have the power to control what you want to send to Sentry(add/filter breadcrumbs, add tags, extra data etc).
In my reactjs app i have a middleware that all the errors are sent there, and inside there there is a logic..
Similarly i d suggest an error middleware where all the errors are send there, and at that middleware you exlicitly handle & send them to Sentry.
I assume the the tech stack node + express, so i d suggest, in the routes catch, to call next(error):
router.get('/path', function(req, res, next){
const getUser = async (id) => {
try {
//do the database operation and return user
} catch (error) {
//return {
// data: null,
// message: e.message
// }
next(error)
}
}
})
**OR based on Express 5, route handlers that return Promise will call next(value) automatically when they reject or throw an error **:
app.get('/path', async function (req, res, next) {
var user = await getUser(id)
res.send(user)
})
And into the app.js, you put the error handler middleware where it handles the errors..:
app.use(function(err, req, res, next){
// filter the error
// send it to Sentry
if(condition){
// add custom breadcrumb
Sentry.addBreadcrumb({
type: Sentry.Severity.Error,
category,
message,
level: Sentry.Severity.Error,
});
Sentry.configureScope((scope: any) => {
scope.setTag('section', section);// add tag
Sentry.captureException(error, scope); // capture the error
});
}
})

How do I handle errors for get API request

I have written an API to view logs of my server in browser. I tried but not getting how to do error handling. Please show how will you do error handling. I am new to node.js
app.get('/logs', function(request, response, next) {
res.sendFile('file', 'path');
});
Error handling looks something like this below.
app.get('/logs', async function(req, res) {
let something;
try {
something = await "file processing";
} catch (error) {
res.status(500).json({ error: error.toString() });
}
res.json({ something });
});
when you are fetching API from other endpoint, you can use promise or async-await
when something goes wrong in the try statement, then error will be catched
if you want to make error deliberately, using new Error() in try statement
you can also study express error middleware when trying to handle route errors.

Catching stripe errors using middleware and logging

I'm curious if there's a good way to handle this with express 4.0.
There are times where there is a problem with either Stripe, or my connection to Stripe that needs to be addressed. However, I obviously do not want users to know about this. I want to display a message 'There was a problem completing your order, please contact support.' while safely logging the message with some information for me to handle it.
I suspect I can do this in middleware. However, I'm not sure how. I would like to catch these errors as they are happening and dump them to a logfile of some kind (suggestions would be great) so I can handle it.
Is there a standard way of doing this? How would I accomplish this?
Thank you!
You're thinking about this the wrong way. Instead of exposing 3rd party errors, explicitly define each possible failure case in your route.
// bad
app.use(function (err, req, res, next) {
res.status(err.status).json({ error: err.message })
})
Instead mark errors to be exposed:
app.use(function (err, req, res, next) {
if (err.expose) {
res.status(err.status).json({ code: err.code, error: err.message })
} else {
reportError(err, req)
res.status(500).json({ code: "unknown", error: "unknown error" })
}
})
You need to re-throw actual api errors.
function createError(status, message) {
var err = new Error(message)
err.expose = true
err.status = status
return err
}
function changeCard(user, data) {
return postStripeCards(user, data)
.catch({ type: "card_error" }, function (err) {
throw createError(400, "invalid card")
})
}
Uncaught errors are programmer mistakes which should be reported and fixed. Anything that makes it through is a bug.
function reportError (err, req) {
// log error
console.error(err.stack)
// send to rollbar
rollbar.handleError(err, req)
// maybe send an email
mailgun.send({
from: "bot#myapp.com",
to: "me#gmail.com",
subject: "My App: " + err.message,
text: err.stack + "\n\n" + JSON.stringify(req),
})
// pager duty, airbrake, etc
}
It takes work, but it means your API is well-defined.

Error handling in Node.js + Express using promises

Using Node.js + Express (4) + Mongoose (using promises rather than callbacks), I can’t sort out how to tidy up my error handling.
What I've got (rather simplified) is:
app.get('/xxx/:id', function(request, response) {
Xxx.findById(request.params.id).exec()
.then(function(xxx) {
if (xxx == null) throw Error('Xxx '+request.params.id+' not found');
response.send('Found xxx '+request.params.id);
})
.then(null, function(error) { // promise rejected
switch (error.name) {
case 'Error':
response.status(404).send(error.message); // xxx not found
break;
case 'CastError':
response.status(404).send('Invalid id '+request.params.id);
break;
default:
response.status(500).send(error.message);
break;
}
});
});
Here, in the switch in the ‘promise rejected’ section, the Error is the error I threw myself for a potentially valid id which is not found, the CastError is Cast to ObjectId failed thrown by Mongoose for an invalid id, and the 500 error can for instance be triggered by mistyping throw Error() as throw Err() (causing a ReferenceError: Err is not defined).
But like this, every one of my routes has this great big clumsy switch to handle the different errors.
How can I centralise the error handling? Can the switch be tucked away into some middleware somehow?
(I did hope I could just re-throw using throw error; within the 'promise rejected' block, but I haven’t been able to make it work).
I would create middleware to handle errors. Using next() for 404s. and next(err) for other errors.
app.get('/xxx/:id', function(req, res, next) {
Xxx.findById(req.params.id).exec()
.then(function(xxx) {
if (xxx == null) return next(); // Not found
return res.send('Found xxx '+request.params.id);
})
.then(null, function(err) {
return next(err);
});
});
404 handler
app.use(function(req, res) {
return res.send('404');
});
Error handler
app.use(function(err, req, res) {
switch (err.name) {
case 'CastError':
res.status(400); // Bad Request
return res.send('400');
default:
res.status(500); // Internal server error
return res.send('500');
}
});
You can improve upon this more by sending a json response like:
return res.json({
status: 'OK',
result: someResult
});
or
return res.json({
status: 'error',
message: err
});

Resources