Nest.js: Can an Exception filters be used in a service?

250 views Asked by At

According to the docs:

Exception filters can be scoped at different levels: method-scoped, controller-scoped, or global-scoped.

Makes me think it can be used at the method level of a service? No?

Example:

dynamo_db.service.ts

import { DynamoDB } from 'aws-sdk';

import { DSDynamoDB } from '@document/utils/aws/dynamodb';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';

@Injectable()
export class DSDynamoDBService {
    constructor(private readonly dynamoDb: DSDynamoDB) {}

@UseFilters(HttpExceptionFilter)
    async putItem(param?: DynamoDB.DocumentClient.PutItemInput): Promise<void> {
        try {
            await this.dynamoDb.getDynamoDBDocClient().put(param).promise();
        } catch (error) {
            throw new NotImplementedException('Update to data failed.', { cause: error, description: 'An Error occured to prevent the data to update.' });
        }
    }

http-exception.filter.ts

import { Request, Response } from 'express';

import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
    catch(exception: HttpException, host: ArgumentsHost): void {
        const response: Response = host.switchToHttp().getResponse<Response>();
        const request: Request = host.switchToHttp().getRequest<Request>();
        const status: number = exception.getStatus();

        response.status(status).json({
            statusCode: status,
            timestamp: new Date().toISOString(),
            path: request.url
        });
    }
}

And here is where that PUT request is happening in my request.logger.interceptor.ts

@Injectable()
export class ReqResLoggerInterceptor implements NestInterceptor {
    constructor(....
    ) {}

    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
            const preventReqResLog: boolean = this.reflector.get<boolean>('preventReqResLog', context.getHandler());

        const isHealthRoute: boolean = originalUrl.endsWith('health/detailed') || originalUrl.endsWith('health');
        try {
            // const tableItem: any = this.dsDocGenerationService.prepareTableItem(body);
            if (!isHealthRoute && !preventReqResLog) {
                this.logService.info(
                    JSON.stringify({
                        originalUrl,
                        method,
                        params,
                        query,
                        headers,
                        requestId: DSRequestContextService.getCurrentReqId(),
                        body
                    })
                );

              /* right here */
                this.dsDynamoDBService.putItem({
                    TableName: this.dsConfig.aws.dynamoDB.table,
                    Item: requestDetails
                });
            }
            (req as any).isLogReqRes = !preventReqResLog;
        } catch (error) {
            this.logService.info(`Saving ${requestDetails} failed.`);
            this.logService.error(error);
        }

        return next.handle().pipe(
            tap((data) => {
                try {
                    if (!isHealthRoute && data) {
                        data.requestId = requestDetails.requestId;
                    }
                    if (!isHealthRoute && !preventReqResLog) {
                        this.logService.info(
                            JSON.stringify({
                                originalUrl,
                                method,
                                params,
                                query,
                                headers,
                                requestId: requestDetails.requestId,
                                statusCode,
                                data
                            })
                        );
                    }
                } catch (error) {
                    this.logService.error(error);
                    console.log('error');
                }
                
    }
}

What happens is when I test it in postman it doesn't error out? Just hangs. My DynamoDB is not connected so shouldn't it fail? And thus I get the error handling message? Any help would be appreciated!

1

There are 1 answers

1
Jay McDoniel On

Makes me think it can be used at the method level of a service? No?

All enhancers (pipes, guards, interceptors, and filters) are only meant to be used on entry points from the framework to your code (i.e. controllers, resolvers, and gateways). There has never been, nor will there be, plans to make enhancers work on services or providers in general.

This like

Exception filters can be scoped at different levels: method-scoped, controller-scoped, or global-scoped.

Method-scope of the controller/resolver/gateway.