#Error handling

1 messages · Page 1 of 1 (latest)

errant turret
#

I always have doubts regarding the handling of errors, I understand that when using a try and catch in a call, if the error occurs, the catch captures it and you handle the error, I wanted to know if there is something that can be done with nest to improve these handling I created something like a global mapper of error instances and I only use try and catch in the controller to capture errors that may occur. Does this seem good or unnecessary ```ts
export class ExceptionMapperService {
static mapToHttpException(error: Error): { status: number; message: string } {
if (error instanceof CategoryNotFoundException) {
throw error;
}

if (error instanceof FileStorageGetUrlException) {
  throw error;
}

if (error instanceof FileStorageRemoveException) {
  throw error;
}

if (error instanceof FileStorageUploadException) {
  throw error;
}

return {
  status: HttpStatus.INTERNAL_SERVER_ERROR,
  message: 'Erro interno do servidor',
};

}
}

#
@HttpCode(204)
  @Delete(':id')
  async remove(@Param('id') id: string): Promise<void> {
    try {
      const clientId = '04a3e89e-cd64-4823-8c3d-da1cbd3c03cd';
      await this.deleteCategoryUseCase.execute(id, clientId);
    } catch (error) {
      const res = ExceptionMapperService.mapToHttpException(error);
      console.log(res);
      throw res;
    }
  }
#
@Injectable()
export class DeleteCategoryUseCase {
  constructor(
    private readonly categoryRepository: CategoryRepository,
    private readonly fileStorageService: FileStorageService,
  ) {}

  async execute(id: string, clientId: string): Promise<void> {
    const category = await this.categoryRepository.getOne(id, clientId);
    if (!category) throw new CategoryNotFoundException();

    await this.fileStorageService.remove(category.imageUrl);
    await this.categoryRepository.delete(category.id);
  }
}
icy mountain
#

Utilize filter exceptions instead. Also mapping isnt a service imo.

#

If you are splitting your logic fron your http layer then be sure that you dont leak those details unless you are 'fine' with it.

rustic eagle
#

error handling can be done in many ways
and nest complicates this with even a few extra methods

##try/catch
a simple try catch can do wonders when you have a chunk of code where on multiple lines things might fail
errors are simply caught and the catch triggers instead
but other then try/catch is then/catch that basicly work the same

this.service.then(() => {
// logic here
}).catch((err: Error) => {
// error handling here
})

##exeption filters
exeption filters are a part of nest
they are basicly its own kind of middleware specially made so you can deal with them
they can run globally or per end point set

##process on
is also something you can use to catch any uncaught error and can be used in your main.ts
but this isn't your silver bullet to try/catch your whole code case
any error caught here will be process even the errors you already caught your self
so i would be verry carefully with this one
and suggest to use it for logging purposes only

process.on('uncaughtException', (err: Error) => {
    logger.error(err)
})

having errors caught on top of erros caught get you in a real mess
something i learned the hard way 😅
i'm now re-wring the whole code base because of that and some other dumb mistakes

error handling can be done at many ways and layers even with nest
but i would suggest to stick to

  • catch errors in either the service or controller not both
  • use interceptors
  • dont chain multiple then()s
    even owasp warns about this
icy mountain
rustic eagle
# icy mountain > > having errors caught on top of erros caught get you in a real mess > someth...

not really since it is in a private gitlab

but dont catch and throw a custom exeption in the service while also doing this in something like a prisma service
that your services depend on

i ended up getting the wrong error codes or error messages/no custom error messages when it should

userService extends mybaseClass that then passes prismaservice in the contractor
where you get some kind of Inheritance mess that also throws exceptions on top of a service that also catches them

icy mountain
# rustic eagle not really since it is in a private gitlab but dont catch and throw a custom ex...

but dont catch and throw a custom exeption in the service while also doing this in something like a prisma service
that your services depend on
Nothing wrong with this though. If you defined a boundary between your logic and data layers then you must translate those errors either way. If there is no boundary then there is no point in mapping your database error to something your logic layer wants considering it depends on your data layer already.

Exception filters aren't complicated at all btw. Most frameworks apply this. Errors bubble up, so its easy to delegate this to something that only handles the mapping of it. Custom errors/exceptions on the otherhand are a complete different topic with endless discussions. You could also just go the Result type way. Depends on the types of errors, what you prefer and who's gonna use it.

e.g.

type Result<TOk, TError> {
  data: TOk,
  error: TError
}

type DeleteCategoryUseCaseResult = Result<void, CategoryNotFoundException | Error>
#

||Result type comes in many ways.||

errant turret
icy mountain
errant turret
#

I understand and it is actually an error if the category is not found in the database. Do you suggest it to be something just like CategoryNotFound?

icy mountain
#

unless, like I said you don't care.

#

also have a look at http problem details!

icy mountain
#

Ah I should probably clarify, by "don't care" I really mean: If your service is only ever going to be used by a http controller then go ahead. Just be consious about it