Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle exceptions in nestjs microservices?

I want to handle exceptions properly in my NestJS app. I have watched videos, read blogs and found some answers on stackoverflow but it is too confusing for me to implement proper exception handling.

The login method in user microservice(controller):

@GrpcMethod('UserService', 'Login')
async login(@Payload() payload: Login): Promise<any> {
    try {
        const { email, password } = payload;
        const { user, token, refreshToken } = await this.usersService.login(email, password);

        return {
            user: {
                email: user.email,
                userId: user.id,
                name: user.name,
                phone: user.phone,
            },
            token,
            refreshToken,
        };
    } catch (error) {
        throw new RpcException(error);
    }
}

The login method in user microservice(service) along with find user by email:

async findByEmail(email: string): Promise<any> {
    const user = this.userModel.findOne({ email }).exec();
    if (!user) return 'User not found!!';
    return user;
}

async login(email: string, password: string): Promise<any> {
    try {
        const user = (await this.findByEmail(email)) as User;

        const comparePassword = await passwordService.comparePasswords(password, user.password);
        if (user && comparePassword) {
            const { token, refreshToken } = await this.sessionService.createSession(user._id, {
                userId: user._id,
                type: user.type,
            });
            return { user, token, refreshToken };
        }
    } catch (error) {
        throw new Error(error);
    }
}

The controller method in API gateway file:

@Post('login')
async login(@Body() loginData: Login): Promise<any> {
    try {
        const user = await firstValueFrom(this.userService.Login(loginData));

        return sendSuccess(user, 'Log-in successful.');
    } catch (error) {
        return sendError(error.details, 404);
    }
}

I want to handle all the exceptions and throw appropriate exception. like if email is not registered then throw "Email not found" if password is wrong then throw "invalid credentials" and so on. How can I do that?

the request-response utility code:

export function sendSuccess<T>(data: T, message: string = 'Success', statusCode: number = HttpStatus.OK): ApiResponse<T> {
    return {
        status: 'success',
        statusCode,
        message,
        data,
    };
}

export function sendError<T>(message: string, statusCode: number): ApiResponse<T> {
    return {
        status: 'error',
        statusCode,
        message,
        data: null,
    };
}

export interface ApiResponse<T> {
    status: 'success' | 'error';
    statusCode: number;
    message: string;
    data: T | null;
}

@Catch()
export class AllExceptionsFilter {
    catch(exception: any, host: ArgumentsHost) {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse<Response>();
        const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
        const message = exception instanceof HttpException ? exception.message : 'Internal Server Error';

        response.status(status).json(sendError(message, status));
    }
}

I have registered AllExceptionsFilter in my main.ts file: app.useGlobalFilters(new AllExceptionsFilter()); but it never gets there.

like image 239
John Oliver Avatar asked Sep 16 '25 05:09

John Oliver


1 Answers

From what I can find in docs AllExceptionsFilter should implements RpcExceptionFilter and uses RpcException for the @Catch decorator.

import { Catch, RpcExceptionFilter, ArgumentsHost } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { RpcException } from '@nestjs/microservices';

@Catch(RpcException)
export class ExceptionFilter implements RpcExceptionFilter<RpcException> {
  catch(
  exception: any, host: ArgumentsHost
): Observable<any> {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
    const message = exception instanceof HttpException ? exception.message : 'Internal Server Error';
    return throwError(() => response.status(status).json(sendError(message, status)););
  }
}

note that

The catch() method must return an Observable

like image 114
Ahmed Sbai Avatar answered Sep 19 '25 15:09

Ahmed Sbai