unified-errors-handler
v3.2.4
Published
Unified Errors Handler is A Powerful Error Handling Library for Node.js that unify error structure across application. it can unify database errors.
Downloads
30
Maintainers
Readme
Unified Errors Handler
Unified Errors Handler is A Powerful Error Handling Library for Node.js that unify error structure across application. it can unify database errors.
Content
- Installation
- Usage
- Errors Structure
- General Exceptions
- SQL Database Exceptions
- No SQL Database Exceptions
- Custom Exceptions
- Logging
- Supported Database and ORMs
- Tests
- Support and Suggestions
Installation
$ npm i unified-errors-handler
Usage
ExpressJS Middleware
const express = require('express');
const { expressExceptionHandler } = require('unified-errors-handler');
const app = express();
/**
response in case of error will be
{
errors: [
{
code: 'USER_NOT_FOUND',
message: 'user not found',
},
],
}
with status code 404
*/
app.post('/test', function (req, res) {
const isFound = // ...
if (isFound) {
// return response
} else {
throw new NotFoundException([
{
code: 'USER_NOT_FOUND',
message: 'user not found',
},
]);
}
});
app.use(expressExceptionHandler());
Custom ExpressJS Middleware
const express = require('express');
const { exceptionMapper } = require('unified-errors-handler');
const app = express();
/**
response in case of error will be
{
errors: [
{
code: 'USER_NOT_FOUND',
message: 'user not found',
},
],
}
with status code 404
*/
app.post('/test', function (req, res) {
const isFound = // ...
if (isFound) {
// return response
} else {
throw new NotFoundException([
{
code: 'USER_NOT_FOUND',
message: 'user not found',
},
]);
}
});
app.use((err: Error, req: any, res: any, next: any) => {
const mappedError = exceptionMapper(err);
res.status(mappedError.statusCode).send({
errors: mappedError.serializeErrors(),
});
});
NestJS Exception Filter
const { exceptionMapper } = require('unified-errors-handler');
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const error = exceptionMapper(exception);
const statusCode = error.statusCode;
response.status(statusCode).json({
errors: error.serializeErrors(),
});
}
}
Options
You can add options to (enable/disable) parsing for database errors (depends on your ORM) this is disabled by default, See supported ORMs
const options = {
mapDBExceptions: true, // deprecated
parseSequelizeExceptions: true,
parseMongooseExceptions: true,
parseTypeORMExceptions: true,
parseObjectionJSExceptions: true,
parseKnexJSExceptions: false,
}
expressExceptionHandler(options)
// or
const mappedError = exceptionMapper(err, options);
Unified Structure
{
errors: [{
fields: ['name', 'password'], // optional
code: 'YOUR_CODE',
message: 'your message'
details: { // optional - more details about error
key: value
}
}]
}
Exceptions
BadRequestException
- Status code - 400
throw new BadRequestException({
fields: ['password'], // optional
code: 'INVALID_PASSWORD', // optional
message: 'invalid password'
details: { // optional
// ... more details
}
});
UnauthorizedException
- Status code - 401
throw new UnauthorizedException({
code: 'UNAUTHORIZED',
message: 'You are not authorized'
});
ForbiddenException
- Status code - 403
throw new ForbiddenException({
code: 'FORBIDDEN',
message: 'You have no access'
});
NotFoundException
- Status code - 404
throw new NotFoundException([
{
code: 'USER_NOT_FOUND',
message: 'user not found',
},
]);
ServerException
- Status code - 500
throw new ServerException();
SQL Database Exceptions
UniqueViolationException
- Status code - 400
// output
[
{
fields: ['name'],
code: 'DATA_ALREADY_EXIST',
message: 'name already exist',
},
]
ForeignKeyViolationException
- Status code - 400
// output
// foreign key is not exist as primary key in another table
// trying insert value with invalid foreign key
[
code: 'INVALID_DATA',
message: 'Invalid data',
details: {
reason: 'violates foreign key constraint',
constraint: 'pet_user_id_foreign',
},
]
// foreign key has reference in another table
[
code: 'DATA_HAS_REFERENCE',
message: 'Data has reference',
details: {
reason: 'violates foreign key constraint',
constraint: 'pet_user_id_foreign',
},
]
NotNullViolationException
- Status code - 400
// output
[
{
fields: ['age'],
code: 'INVALID_DATA',
message: 'age is invalid',
details: { reason: 'age must not be NULL' },
},
]
CheckViolationException
- Status code - 400
- Example - Invalid enum value
// output
[{
code: 'INVALID_VALUES',
message: 'Invalid Values',
details: {
constraint: 'user_gender_check',
},
}]
OutOfRangeViolationException
- Status code - 400
- Example - numeric value out of range
// output
[{
{
code: 'OUT_OF_RANGE',
message: 'Out of range',
},
}]
No SQL Database Exceptions
MongoDBUniqueViolationException
- Status code - 400
// output
[
{
fields: ['name'],
values: ['Ahmed'],
code: 'DATA_ALREADY_EXIST',
message: 'name already exist',
},
]
MongooseValidationException
- Status code - 400
// output
[
// field is required
{
fields: ['age'],
message: 'Path `age` is required.',
code: 'MONGODB_VALIDATION_ERROR',
details: {
reason: 'age is required',
violate: 'required_validation'
},
},
// field's value violate enum values
{
fields: ['gender'],
message: '`MALEE` is not a valid enum value for path `gender`.',
code: 'MONGODB_VALIDATION_ERROR',
details: {
reason: "gender's value must be one of MALE, FEMALE",
violate: 'enum_validation'
},
},
// field's value violate max value
{
fields: ['age'],
message: 'Path `age` (300) is more than maximum allowed value (50).',
code: 'MONGODB_VALIDATION_ERROR',
details: {
reason: `age's value exceed maximum allowed value (50)`,
violate: 'max_validation'
},
},
// field's value violate min value
{
fields: ['age'],
message: 'Path `age` (3) is less than minimum allowed value (20).',
code: 'MONGODB_VALIDATION_ERROR',
details: {
reason: `age's value less than minimum allowed value (20)`,
violate: 'min_validation'
},
},
// field's value violate type of field
{
fields: ['age'],
message: 'age is invalid',
code: 'MONGODB_CASTING_ERROR',
},
]
Custom Exceptions
You can create your own exceptions by extend BaseException
export class MyCustomException extends BaseException {
statusCode = 400;
constructor(private message: string) {
super(message);
Object.setPrototypeOf(this, MyCustomException.prototype);
}
serializeErrors() {
return [{
message,
code: 'CUSTOM_CODE'
}];
}
}
Logging
ConsoleLogger
const options = {
loggerOptions: {
console: {
format: ':time :message', // optional - default message only
colored: true, // optional - default no color
},
},
}
expressExceptionHandler(options)
// or
const mappedError = exceptionMapper(err, options);
CustomLogger
implement ILogger interface
import { ILogger } from 'unified-errors-handler';
class CustomLogger implements ILogger {
log(error: any): void {
console.log(error.message);
}
}
// in options pass this object
const options = {
loggerOptions: {
custom: new CustomLogger(),
},
}
expressExceptionHandler(options)
// or
const mappedError = exceptionMapper(err, options);
Supported Database and ORMs
- MYSQL with TypeORM
- Postgres with TypeORM
- MYSQL with Sequelize
- Postgres with Sequelize
- MYSQL with ObjectionJS
- Postgres with ObjectionJS
- MYSQL with KnexJS
- Postgres with KnexJS
- MongoDB with Mongoose
Tests
To run the test suite,
- first install the dependencies
- rename .env.sample to .env
- You can run
docker-comose up
or set your own connection URLs for postgres database and mysql database in .env - run
npm test
:
$ npm install
$ npm test
Support and Suggestions
Feel free to open issues on github.