mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-10 15:17:41 +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 { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
|
||||||
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { OAuth2Client } from 'google-auth-library';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
|
@ -6,10 +6,16 @@ import { AuthModule } from './auth/auth.module';
|
|||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import { EmailService } from './util/email.service';
|
import { EmailService } from './util/email.service';
|
||||||
|
import { ErrorMessageService } from 'src/error-message/error-message.service';
|
||||||
@Module({
|
@Module({
|
||||||
providers: [CommonService, EmailService],
|
providers: [CommonService, EmailService, ErrorMessageService],
|
||||||
exports: [CommonService, HelperModule, AuthModule, EmailService],
|
exports: [
|
||||||
|
CommonService,
|
||||||
|
HelperModule,
|
||||||
|
AuthModule,
|
||||||
|
EmailService,
|
||||||
|
ErrorMessageService,
|
||||||
|
],
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
load: config,
|
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 { ValidationPipe } from '@nestjs/common';
|
||||||
import { json, urlencoded } from 'body-parser';
|
import { json, urlencoded } from 'body-parser';
|
||||||
import { SeederService } from '@app/common/seed/services/seeder.service';
|
import { SeederService } from '@app/common/seed/services/seeder.service';
|
||||||
|
import { HttpExceptionFilter } from './common/filters/http-exception/http-exception.filter';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
@ -15,6 +16,7 @@ async function bootstrap() {
|
|||||||
// Set the body parser limit to 1 MB
|
// Set the body parser limit to 1 MB
|
||||||
app.use(json({ limit: '1mb' }));
|
app.use(json({ limit: '1mb' }));
|
||||||
app.use(urlencoded({ limit: '1mb', extended: true }));
|
app.use(urlencoded({ limit: '1mb', extended: true }));
|
||||||
|
app.useGlobalFilters(new HttpExceptionFilter());
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
rateLimit({
|
rateLimit({
|
||||||
|
@ -3,9 +3,10 @@ import { RegionService } from './services/region.service';
|
|||||||
import { RegionController } from './controllers/region.controller';
|
import { RegionController } from './controllers/region.controller';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||||
|
import { CommonModule } from '@app/common';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule, CommonModule],
|
||||||
controllers: [RegionController],
|
controllers: [RegionController],
|
||||||
providers: [RegionService, RegionRepository],
|
providers: [RegionService, RegionRepository],
|
||||||
exports: [RegionService],
|
exports: [RegionService],
|
||||||
|
@ -2,23 +2,33 @@ import {
|
|||||||
BadRequestException,
|
BadRequestException,
|
||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||||
|
import { ErrorMessageService } from 'src/error-message/error-message.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RegionService {
|
export class RegionService {
|
||||||
constructor(private readonly regionRepository: RegionRepository) {}
|
constructor(
|
||||||
|
private readonly regionRepository: RegionRepository,
|
||||||
|
@Inject(ErrorMessageService)
|
||||||
|
private readonly errorMessageService: ErrorMessageService,
|
||||||
|
) {}
|
||||||
async getAllRegions() {
|
async getAllRegions() {
|
||||||
try {
|
try {
|
||||||
const regions = await this.regionRepository.find();
|
const regions = await this.regionRepository.find();
|
||||||
|
|
||||||
return regions;
|
return regions;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof BadRequestException) {
|
if (err instanceof BadRequestException) {
|
||||||
throw err; // Re-throw BadRequestException
|
throw err; // Re-throw BadRequestException
|
||||||
} else {
|
} 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