mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-09 22:57:24 +00:00
added a dedicated error handler service
This commit is contained in:
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -0,0 +1,7 @@
|
||||
import { HttpExceptionFilter } from './http-exception.filter';
|
||||
|
||||
describe('HttpExceptionFilter', () => {
|
||||
it('should be defined', () => {
|
||||
expect(new HttpExceptionFilter()).toBeDefined();
|
||||
});
|
||||
});
|
38
src/common/filters/http-exception/http-exception.filter.ts
Normal file
38
src/common/filters/http-exception/http-exception.filter.ts
Normal 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);
|
||||
}
|
||||
}
|
18
src/error-message/error-message.service.spec.ts
Normal file
18
src/error-message/error-message.service.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
40
src/error-message/error-message.service.ts
Normal file
40
src/error-message/error-message.service.ts
Normal 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;
|
||||
}
|
||||
}
|
@ -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({
|
||||
|
@ -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],
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user