added a dedicated error handler service

This commit is contained in:
unknown
2024-10-04 22:04:19 +03:00
parent a311286430
commit 553f08641e
9 changed files with 130 additions and 7 deletions

View File

@ -6,6 +6,7 @@ import { UserRepository } from '../../../../common/src/modules/user/repositories
import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
import { ConfigService } from '@nestjs/config';
import { OAuth2Client } from 'google-auth-library';
@Injectable()
export class AuthService {

View File

@ -6,10 +6,16 @@ import { AuthModule } from './auth/auth.module';
import { ConfigModule } from '@nestjs/config';
import config from './config';
import { EmailService } from './util/email.service';
import { ErrorMessageService } from 'src/error-message/error-message.service';
@Module({
providers: [CommonService, EmailService],
exports: [CommonService, HelperModule, AuthModule, EmailService],
providers: [CommonService, EmailService, ErrorMessageService],
exports: [
CommonService,
HelperModule,
AuthModule,
EmailService,
ErrorMessageService,
],
imports: [
ConfigModule.forRoot({
load: config,

View File

@ -0,0 +1,7 @@
import { HttpExceptionFilter } from './http-exception.filter';
describe('HttpExceptionFilter', () => {
it('should be defined', () => {
expect(new HttpExceptionFilter()).toBeDefined();
});
});

View File

@ -0,0 +1,38 @@
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { Response } from 'express';
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message =
exception instanceof HttpException
? exception.getResponse()
: 'Internal server error';
const errorResponse = {
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
error: message,
};
// Optionally log the exception
console.error(`Error occurred:`, exception);
response.status(status).json(errorResponse);
}
}

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ErrorMessageService } from './error-message.service';
describe('ErrorMessageService', () => {
let service: ErrorMessageService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ErrorMessageService],
}).compile();
service = module.get<ErrorMessageService>(ErrorMessageService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,40 @@
// src/common/services/error-message.service.ts
import { Injectable } from '@nestjs/common';
type ErrorMessageKey = keyof typeof ErrorMessageService.prototype.messages;
@Injectable()
export class ErrorMessageService {
public readonly messages = {
NOT_FOUND: '{entity} not found', // Single key for "not found" errors
INVALID_MINUTES: 'Invalid minutes value',
INVALID_TIME_FORMAT: 'Invalid time format',
USER_NOT_FOUND: '{entity} not found', // Can reuse NOT_FOUND if desired
INTERNAL_SERVER_ERROR: 'Internal server error',
ERROR_ADDING_TEMP_PASSWORD:
'Error adding {type} temporary password from Tuya',
INVALID_UUID: 'Invalid {entity} UUID',
USER_ALREADY_BELONGS: 'This user already belongs to this {entity}',
USER_HAS_NO_ENTITIES: 'This user has no {entity}',
DEVICE_OPERATION_FAILED: 'All device operations failed',
REQUEST_FAILED: 'Error processing {operation} request',
COOLDOWN_ERROR:
'Please wait {time} more seconds before requesting a new OTP.',
};
getMessage(
key: ErrorMessageKey,
params?: Record<string, string | number>,
): string {
let message = this.messages[key] || 'Unknown error';
// Replace placeholders with provided params
if (params) {
Object.keys(params).forEach((param) => {
const regex = new RegExp(`{${param}}`, 'g');
message = message.replace(regex, params[param].toString());
});
}
return message;
}
}

View File

@ -6,6 +6,7 @@ import { setupSwaggerAuthentication } from '../libs/common/src/util/user-auth.sw
import { ValidationPipe } from '@nestjs/common';
import { json, urlencoded } from 'body-parser';
import { SeederService } from '@app/common/seed/services/seeder.service';
import { HttpExceptionFilter } from './common/filters/http-exception/http-exception.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
@ -15,6 +16,7 @@ async function bootstrap() {
// Set the body parser limit to 1 MB
app.use(json({ limit: '1mb' }));
app.use(urlencoded({ limit: '1mb', extended: true }));
app.useGlobalFilters(new HttpExceptionFilter());
app.use(
rateLimit({

View File

@ -3,9 +3,10 @@ import { RegionService } from './services/region.service';
import { RegionController } from './controllers/region.controller';
import { ConfigModule } from '@nestjs/config';
import { RegionRepository } from '@app/common/modules/region/repositories';
import { CommonModule } from '@app/common';
@Module({
imports: [ConfigModule],
imports: [ConfigModule, CommonModule],
controllers: [RegionController],
providers: [RegionService, RegionRepository],
exports: [RegionService],

View File

@ -2,23 +2,33 @@ import {
BadRequestException,
HttpException,
HttpStatus,
Inject,
Injectable,
} from '@nestjs/common';
import { RegionRepository } from '@app/common/modules/region/repositories';
import { ErrorMessageService } from 'src/error-message/error-message.service';
@Injectable()
export class RegionService {
constructor(private readonly regionRepository: RegionRepository) {}
constructor(
private readonly regionRepository: RegionRepository,
@Inject(ErrorMessageService)
private readonly errorMessageService: ErrorMessageService,
) {}
async getAllRegions() {
try {
const regions = await this.regionRepository.find();
return regions;
} catch (err) {
if (err instanceof BadRequestException) {
throw err; // Re-throw BadRequestException
} else {
throw new HttpException('Regions found', HttpStatus.NOT_FOUND);
throw new HttpException(
this.errorMessageService.getMessage('NOT_FOUND', {
entity: 'Regions',
}),
HttpStatus.NOT_FOUND,
);
}
}
}