问题
While using NestJS to create API's I was wondering which is the best way to handle errors/exception. I have found two different approaches :
- Have individual services and validation pipes
throw new Error()
, have the controllercatch
them and than throw the appropriate kind ofHttpException
(BadRequestException
,ForbiddenException
etc..) - Have the controller simply call the service/validation pipe method responsible for handling that part of business logic, and throw the appropriate
HttpException
.
There are pros and cons to both approeaches:
- This seems the right way, however, the service can return
Error
for different reasons, how do I know from the controller which would be the corresponding kind ofHttpException
to return? - Very flexible, but having
Http
related stuff in services just seems wrong.
I was wondering, which one (if any) is the "nest js" way of doing it ?
How do you handle this matter?
回答1:
Let's assume your business logic throws an EntityNotFoundError
and you want to map it to a NotFoundException
.
For that, you can create an Interceptor that transforms your errors:
@Injectable()
export class NotFoundInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// next.handle() is an Observable of the controller's result value
return next.handle()
.pipe(catchError(error => {
if (error instanceof EntityNotFoundError) {
throw new NotFoundException(error.message);
} else {
throw error;
}
}));
}
}
You can then use it by adding @UseInterceptors(NotFoundInterceptor)
to your controller's class or methods; or even as a global interceptor for all routes. Of course, you can also map multiple errors in one interceptor.
Try it out in this codesandbox.
回答2:
You may want to bind services not only to HTTP interface, but also for GraphQL or any other interface. So it is better to cast business-logic level exceptions from services to Http-level exceptions (BadRequestException, ForbiddenException) in controllers.
In the simpliest way it could look like
import { BadRequestException, Injectable } from '@nestjs/common';
@Injectable()
export class HttpHelperService {
async transformExceptions(action: Promise<any>): Promise<any> {
try {
return await action;
} catch (error) {
if (error.name === 'QueryFailedError') {
if (/^duplicate key value violates unique constraint/.test(error.message)) {
throw new BadRequestException(error.detail);
} else if (/violates foreign key constraint/.test(error.message)) {
throw new BadRequestException(error.detail);
} else {
throw error;
}
} else {
throw error;
}
}
}
}
and then
来源:https://stackoverflow.com/questions/51112952/what-is-the-nestjs-error-handling-approach-business-logic-error-vs-http-error