I used Objection.js as ORM for my Nest.js app. I tried to implement global error handling for both Http exception and Objection Error (ORM / Database Error). Suppose I make a mistake inserting a same unique value, it would throw UniqueViolationError
. But every time I throw error on the users.service.ts
(users module service) part of the app, on the service the error still an instance of UniqueViolationError
but on filters it became the instance of HttpExceptionError
thus my filters won't work. Here is the full code :
errors.filters.ts
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
InternalServerErrorException,
} from '@nestjs/common';
import {
ValidationError,
NotFoundError,
DBError,
ConstraintViolationError,
UniqueViolationError,
NotNullViolationError,
ForeignKeyViolationError,
CheckViolationError,
DataError,
} from 'objection';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: InternalServerErrorException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
// All the errors here are instance of HttpException, it shouldn't be :(
if (exception instanceof ValidationError) {
switch (exception.type) {
case 'ModelValidation':
response.status(HttpStatus.BAD_REQUEST).send({
message: exception.message,
type: exception.type,
data: exception.data,
timestamp: new Date().toISOString(),
statusCode: HttpStatus.BAD_REQUEST,
path: request.url,
});
break;
case 'RelationExpression':
response.status(HttpStatus.BAD_REQUEST).send({
message: exception.message,
type: 'RelationExpression',
data: {},
timestamp: new Date().toISOString(),
statusCode: HttpStatus.BAD_REQUEST,
path: request.url,
});
break;
case 'UnallowedRelation':
response.status(HttpStatus.BAD_REQUEST).send({
message: exception.message,
type: exception.type,
data: {},
timestamp: new Date().toISOString(),
statusCode: HttpStatus.BAD_REQUEST,
path: request.url,
});
break;
case 'InvalidGraph':
response.status(HttpStatus.BAD_REQUEST).send({
message: exception.message,
type: exception.type,
data: {},
timestamp: new Date().toISOString(),
statusCode: HttpStatus.BAD_REQUEST,
path: request.url,
});
break;
default:
response.status(HttpStatus.BAD_REQUEST).send({
message: exception.message,
type: 'UnknownValidationError',
data: {},
timestamp: new Date().toISOString(),
statusCode: HttpStatus.BAD_REQUEST,
path: request.url,
});
break;
}
} else if (exception instanceof ConstraintViolationError) {
response.status(HttpStatus.BAD_REQUEST).json({
statusCode: HttpStatus.BAD_REQUEST,
timestamp: new Date().toISOString(),
message: exception.message,
type: 'ConstraintViolation',
path: request.url,
});
} else if (exception instanceof DBError) {
response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
timestamp: new Date().toISOString(),
message: exception.message,
type: 'UnknownDBError',
path: request.url,
});
} else if (exception instanceof DataError) {
response.status(HttpStatus.BAD_REQUEST).json({
statusCode: HttpStatus.BAD_REQUEST,
timestamp: new Date().toISOString(),
message: exception.message,
type: 'InvalidData',
path: request.url,
});
} else if (exception instanceof CheckViolationError) {
response.status(HttpStatus.BAD_REQUEST).json({
statusCode: HttpStatus.BAD_REQUEST,
timestamp: new Date().toISOString(),
message: exception.message,
type: 'CheckViolation',
path: request.url,
});
} else if (exception instanceof ForeignKeyViolationError) {
response.status(HttpStatus.BAD_REQUEST).json({
statusCode: HttpStatus.BAD_REQUEST,
timestamp: new Date().toISOString(),
message: exception.message,
type: 'ForeignKeyViolation',
path: request.url,
});
} else if (exception instanceof NotNullViolationError) {
response.status(HttpStatus.BAD_REQUEST).json({
statusCode: HttpStatus.BAD_REQUEST,
timestamp: new Date().toISOString(),
message: exception.message,
type: 'NotNullViolation',
path: request.url,
});
} else if (exception instanceof UniqueViolationError) {
response.status(HttpStatus.CONFLICT).json({
statusCode: HttpStatus.CONFLICT,
message: exception.message,
timestamp: new Date().toISOString(),
type: 'UniqueViolation',
path: request.url,
});
} else if (exception instanceof NotFoundError) {
response.status(HttpStatus.NOT_FOUND).json({
statusCode: HttpStatus.NOT_FOUND,
timestamp: new Date().toISOString(),
message: exception.message,
type: 'NotFound',
path: request.url,
});
} else if (exception instanceof HttpException) {
response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
message: exception.message,
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
type: 'HttpServerError',
timestamp: new Date().toISOString(),
path: request.url,
});
} else {
response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
type: 'UnknownErrorServer',
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
}
main.ts
import 'dotenv/config';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import * as requestIp from 'request-ip';
import { ValidationPipe } from '@nestjs/common';
import { AllExceptionsFilter } from './filters/errors.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(requestIp.mw());
app.enableCors();
app.useGlobalPipes(
new ValidationPipe({
transform: true,
}),
);
app.useGlobalFilters(new AllExceptionsFilter());
// swagger documentations
const config = new DocumentBuilder()
.setTitle('SWAGGER')
.setDescription('SWWAAAAG')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('docs', app, document);
await app.listen(4040);
}
bootstrap();
functions on users.service.ts
try {
await this.modelQuery.query().insert({ name: 'Same name' })
} catch (error) {
// in here still UniqueViolationError
throm new Error(error)
}
Why the error instance changed and how to make it not change? What do I do wrong here?