I want to create an errorHandler middleware for my app. I used KoaJs for my web application and my error basic handler function like that:
error-handler.ts:
import { Context } from "koa";
export const errorHandler : any = (err : Error, ctx : Context ) =>{
console.log("Something went wrong") ====>>> Its Work
ctx.status = 403. ========>>>> Not work
ctx.body = "asdasd" =========>>>> Not work
}
And my endpoint which used error handler like that:
public static async helloWorld(ctx: BaseContext): Promise<void> {
throw new Error ('Error Here');
}
And my app.js like that:
import Koa from "koa";
import { errorHandler } from './middleware/error-handler';
...
app.use(errorHandler)
...
And When I send request to endpoint I getting an error like that :
Why Im getting this error? How can I solve this problem?
Your error handler does not work, because you are not catching the error.
Your code works as follows:
As you have a use(errorHandler) and in the error handler no await next(), your complete error handler is executed first (no matter if there is an error or not). Then your helloWorld function is executed. And as there is an uncatched error, Koa does reply a 404 not found to the client.
How it should be:
Your errorHandler should have a await next(), then afterwards it needs to check if there is an error. If yes, then this needs to be captured and then you can specify status code and resulting body.
Possible solution:
I guess your errorHandler should look more like this:
export const errorHandler : any = async (ctx : Context, next ) =>{
try {
await next();
} catch (err) {
console.log("Something went wrong");
ctx.status = 403;
ctx.body = err;
}
}
Related
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
});
}
})
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;
}
}
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.
I have created nodejs + express application. Now in my application when exception caught errors are send as follows
app.get('/data', (req, res) => {
if(!req.params.token){
return res.status(403).send('Access token not provided');
}
//do something here
});
Instead of sending res.status(403).send('Access token not provided'); can I send something like this
exception.js
class Forbidden {
constructor(message,stack = null){
this.code = 403;
this.message = message
this.stack = stack;
}
}
app.js
var httpForbidden = require('exception.js');
app.get('/data', (req, res) => {
if(!req.params.token){
return new httpForbidden ('Access token not provided');
}
//do something here
});
And also how can I caught all exceptions in once place ?
You could use something like this:
class httpError {}
class httpForbidden extends httpError {
constructor(message, stack = null) {
super();
this.code = 403;
this.message = message
this.stack = stack;
}
}
app.get('/', (req, res) => {
if (!req.params.token) {
throw new httpForbidden('Access token not provided');
}
...
});
app.use((err, req, res, next) => {
if (err instanceof httpError) {
return res.status(err.code).send(err.message);
}
res.sendStatus(500);
});
This uses an Express error handling middleware that will check if the error that got thrown is an instance of httpError (which would be the superclass of all the HTTP error classes that you'd want to create) and, if so, would generate a particular response according to the code and the message (or generate a generic 500 error response otherwise).
I like to create a separate function, along with other utility functions ( say in lib.js), which creates a properly formatted JSON response object and selects the appropriate logger to log response depending upon the HTTP status code.
lib.js
var logger = require("./loggger");
module.exports.sendResponse = function (res,code,message,data) {
if(code<100 || code>599) {
throw new Error("response cannot be sent. Invalid http-code was provided.");
}
var responseLogger = code>=500 ? logger.error : logger.debug;
var responseObject = {
"code" : code,
"message" : message
};
if(data) {
responseObject.data = data;
}
responseLogger(responseObject);
res.status(code).json(responseObject);
};
app.js
var lib = require("./lib");
/*
Relevant Express server code
*/
app.get('/data', function (req,res) {
if(!req.params.token){
return lib.sendResponse(res,403,"Access token not provided");
}
// Rest of business logic
});
Note : You can write your own logging functionality, but I strongly suggest to build it upon some standard logging library like winston)
Below method is deprecated as the boom is changes to #hapi/boom,
https://hapi.dev/family/boom/?v=8.0.1
here you find whole documentation of #hapi/boom library
-----deprecated-------
You can use boom library instead, which provides a set of utilities for returning HTTP errors
HTTP 4xx Errors
Boom.badRequest([message], [data])
Boom.unauthorized([message],[scheme], [attributes])
HTTP 5xx Errors
Boom.badImplementation([message], [data]) - (alias: internal)
Boom.notImplemented([message], [data])
for more api documentation visit here
You can use:
res.code(403).json({message: '...', stack: '...'});
and send whatever you want. But you do it with calling methods on the response object.
And also how can I caught all exceptions in once place ?
Very bad idea. You should handle all errors where they happen so that you can still have some context to handle them in a reasonable way. Otherwise you can just throw exceptions and return 500 errors.
Currently I have a middleware using Express but I can't launch an error with the same format Express uses because it's a sync function so things like next(err) simply doesn't work.
I could send an error with throw and the application does not crash so it's fine, but I cant set some params such as err.message or err.statusCode. This is the code working:
function getScope(req, res, next){
//req.scopesArray is an array of arrays: [ ['RESOURCE','.ACTION'] , ['patient','.create'] ]
req.scopesArray.forEach(function(current,index,array){
switch(req.scopesArray){
case 'user': var hasPermissions = checkUserPermissions(permissionId,action); break;
}
if(!hasPermissions) throw new Error('Error with permissions');
});
next();
}
I've realized that, event not calling next(err), the error middleware does execute.
I've tried thinks like:
var err = {}; err.message = 'test'; err.statusCode=404;
throw new Error(err);
But has not worked.
How could I send an async error to the error middleware but being able to set err values? Thanks.