npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

demo-nest-auth

v0.2.13

Published

http://10.10.11.120:4873/ verdaccio

Downloads

6

Readme

http://10.10.11.120:4873/ verdaccio

Экспепшены влияют ли на control flow? Конкретные примеры: ошибка верификации jwt-токена. пользователь с указанным id не найден в базе. (Его просто нет) Это исключения или нет.

Nest с его HttpExceptions и exception filter подталкивает нас к тому, что эксепшен - любая ситуация, которая должна прекратить обработку запроса (неверный токен, отсутствие прав, что угодно ещё)

try/catch в сервисе - это вовсе не control flow, это именно проброс с заворачиванием.

Example 1

try {
  const isVerified = Jwt.verify(...);
  if (!isVerified) {
    throw new AuthException()
    // Или сразу res.send?
    // Или throw ForbiddenHttpException, чтобы потом его exception filter отловил.
  }
}
catch (err) {
  // Тут надо разбираться, что это за ошибка.
  // Может это auth ошибка?
}

Example 2

try {
  await Jwt.verify(token) // will throw error if token is invalid
}
catch (err){
  wrap(err).throwAs(AuthException) // will throw AuthException with inner exception being the one thrown by verify.

}

Обработка ошибок в домене (модуле)

Классы ошибок


Внутри домена могут возникать различные исключительные ситуации. Например попытка добавить в базу пользователся с уже существующим адресом эл. почты.

В этом случае контроллер (или сервис) должен выбросить соответствующее исключение, например:

throw new EmailAlreadyExistsException(email);

Классы исключений для домена создаются в файле [domainName].errors.ts (или разбиваются на несколько файлов, если их много).

Все классы исключений должны быть унаследованы от общего для домена класса [domainName]Exception (DriverException в данном примере), который в свою очередь наследуется от класса DomainException из пакета @skeleton/errors

export class DriverException extends DomainException {
  constructor(msg: string, inner?: ErrorLike) {
    super(msg, inner); // Or some custom logic.
  }
}

export class EmailAlreadyExistsException extends DriverException {
  constructor(email: string) {
    super(`User with email <${email}> already exists`);
  }
}

Класс DomainException преставляет собой простую обёртку над стандартным js-объектом Error, позволяющую вкладывать внутрь другой объект ошибки.

Например:

try {
  // do something with datadase that throws some DB error;
} catch (err) {
  // err - some data access layer error
  throw new DriverException(err.message, err);
}

В таком сценарии, когда наш DriverException будет отловлен в интерсепторе (см. ниже), внутри будет содержаться более низкоуровневая ошибка (со стеком и прочими данными), что удобно для логирования и отладки.


Маппинг ошибок и HttpExceptionFilter


За формирования ответа пользователю отвечает контроллер. Но, чтобы не загружать каждый контроллер логикой по обработке всех видов ошибок в nesjs существует концепция Exception-фильтров.

Пакет @skeleton/errors содержит два фильтра, подключаемых по умолчанию:

  1. UnhandledErrorsFilter - отвечает за формирование ответа сервера в случае необработанных исключений.
  2. HttpExceptionFilter - отвечает за формирование ответа в случае выброшенных HttpException.

Благодаря п. 2, разработчику не нужно заботиться о формировании ответа в случае различных доменных ошибок. Достаточно просто выбросить нужный HttpException (например NotFoundException или ForbiddenException) с необходимой информацией внутри.

Какие ошибки в каком случае выбрасывать мы можем указать в перехватчике (interceptor).


DomainError interceptors (перехватчики исключений)


Перехватчик - особый класс в nestjs, которая может трансформировать данные (и исключения) происходящие во время обработки запроса.

Важный момент, установленный опытным путём: исключения выбрасываемые в middleware (то есть до начала обработки запроса как такового) отловить интерцептором нельзя.

Поэтому в таких случаях маппинг приходится делать прямо в middleware.

Перехватчики могут использоваться для разных целей. В данном случае мы используем их для того, чтобы указать, при каких доменных ошибках, какие HttpException следует выбрасывать (и, соответственно, какие ответы клиенту отправлять).


@Injectable()
export class DriverExceptionsInterceptor implements NestInterceptor {

  constructor(
    private readonly logger: AppLog
  ) { }

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    
    return next.handle()
      .pipe(catchError(err => {
        // Logging domain error
        this.logger.error(err.toString());

        // Mapping it to HttpException
        if (err instanceof DriverException) {
          return throwError(new BadRequestException(err.message))
        } else if (....
          ....
        }

        /* If err is some unknown exception we
        just throw it. In the end it will be caught
        by UnhandledExceptionFilter */ 
        return throwError(err);
      }));
  }
}

next.handle() предоставляет доступ к Observable (потоку) в которой попадёт наше доменное исключение. При помощи метода catchError мы получаем саму ошибку и в зависимости от требований конкретной ситуации выбрасываем соответствущий HttpException.