Я большой поклонник того, как stestjs обрабатывать проверку, используя библиотеку класса-валидатора. Существует много преимуществ использования внешней библиотеки для проверки. Для большинства типичных случаев интеграция по умолчанию через ВалидацияПипе
достаточно хорош. Но, как вы знаете, ежедневная работа любит проверять и вызов нам.
Несколько дней назад у меня была определенная потребность – мне нужно было проверить что-то с помощью ValidatorPipe и библиотеки классно-валидатора, но одним из факторов проверки было идентификатором пользователя. В этом проекте идентификатор пользователя выталкивается из токена JWT во время процесса авторизации и добавляется к объекту запроса.
Моя первая мысль была – просто используйте объем запроса на инъекцию, как мы можем сделать это в Subsjs Services:
constructor(@Inject(REQUEST) private request: Request) {}
Очевидно, – это не работает, в противном случае эта статья не будет здесь. Вот краткое объяснение Сделано Bestjs Creator, Kamil Myśliwec:
Ok. Таким образом, в основном нет простого способа получить запрос объекты данных в пользовательском ограничитении проверки. Но есть путь! Не идеально, но это работает. И если это не может быть красиво, по крайней мере, это должно сделать свою работу. Какие шаги нам нужно взять, чтобы добиться этого?
- Создать перехватчик, который добавит объект пользователя к нужному вам нужен (запрос, тело или параметр)
- Напишите свое ограничение Validator, расширенные аргументы проверки аргументов, используйте необходимые вам данные пользователя.
- Создайте трубу, которая раскроет объект типа запроса из пользовательского контекста данных.
- Создайте соответствующие декораторы, один для каждого типа запроса.
- Используйте вновь созданные декораторы в контроллерах, когда вам нужно «вводить» пользовательские данные в ваш класс валидации.
Не отлично, не ужасно. Верно?
Перехватчик
Создайте перехватчик, который добавит объект пользователя к нужным вам типа (запрос, тело или параметр). Для демонстрационных целей я предполагаю, что вы храните свой пользовательский объект в request.user
атрибут.
export const REQUEST_CONTEXT = '_requestContext'; @Injectable() export class InjectUserInterceptor implements NestInterceptor { constructor(private type?: Nullable<'query' | 'body' | 'param'>) {} intercept(context: ExecutionContext, next: CallHandler): Observable{ const request = context.switchToHttp().getRequest(); if (this.type && request[this.type]) { request[this.type][REQUEST_CONTEXT] = { user: request.user, }; } return next.handle(); } }
Пользовательский декоратор проверки
Напишите свой ограниченный навязку и пользовательский декоратор, расширенные аргументы проверки аргументов, используйте необходимые вами данные пользователя.
@ValidatorConstraint({ async: true }) @Injectable() export class IsUserCommentValidatorConstraint implements ValidatorConstraintInterface { constructor(private commentsRepository: CommentsRepository) {} async validate(commentId: number, args?: ExtendedValidationArguments) { const userId = args?.object[REQUEST_CONTEXT].user.id; if (userId && Number.isInteger(commentId)) { const comment = await this.commentsRepository.findByUserId(userId, commentId); // Checking if comment belongs to selected user if (!comment) { return false; } } return true; } defaultMessage(): string { return 'The comment does not belong to the user'; } } export function IsUserComment(validationOptions?: ValidationOptions) { return function (object: any, propertyName: string) { registerDecorator({ name: 'IsUserComment', target: object.constructor, propertyName: propertyName, options: validationOptions, validator: IsUserCommentValidatorConstraint, }); }; }
Если вы не знаете, как вводить зависимости в пользовательский валидатор в библиотеке класса-валидатора, эта статья может помочь вам.
Мой ExtendedValidationarguments
Интерфейс выглядит так:
export interface ExtendedValidationArguments extends ValidationArguments { object: { [REQUEST_CONTEXT]: { user: IUser; // IUser is my interface for User class }; }; }
Это позволяет мне использовать действительные ввода в ValidatorConstraint
Отказ Без этого TypeScript распечатает ошибку, что _requestcontext
Собственность не существует.
Зачистка трубы
Создайте трубу, которая раскроет объект типа запроса из пользовательского контекста данных. Если мы этого не сделаем, наш объект DTO будет содержать прикрепленные ранее данные запроса. Мы не хотим, чтобы это произошло. Я использую здесь один из Лоташ
Функция – Опустите () Отказ Это позволяет удалить выбранные свойства от объекта.
@Injectable() export class StripRequestContextPipe implements PipeTransform { transform(value: any) { return omit(value, REQUEST_CONTEXT); } }
Новые декораторы
Создание новых декоративов нет необходимости, но это определенно более чистый и сухой подход, чем вручную добавлять перехватчики и трубы к способам. Мы собираемся использовать встроенный функцию nestjs – NatsoDeCoraters
, который Позволяет объединять несколько разных декораторов в новый Отказ
export function InjectUserToQuery() { return applyDecorators(InjectUserTo('query')); } export function InjectUserToBody() { return applyDecorators(InjectUserTo('body')); } export function InjectUserToParam() { return applyDecorators(InjectUserTo('params')); } export function InjectUserTo(context: 'query' | 'body' | 'params') { return applyDecorators(UseInterceptors(new InjectUserInterceptor(context)), UsePipes(StripRequestContextPipe)); }
Чтобы добавить свои пользовательские данные, просто украсьте метод вашего контроллера одним из вышеперечисленных декоративов.
@InjectUserToParam() async edit(@Param() params: EditParams){}
Теперь, если вы хотите использовать свой IsuserComment
Декоратор в EditParams
, вы сможете получить доступ к введенным пользовательским данным.
export class EditParams { @IsUserComment() commentId: number; }
И это все! Вы можете использовать этот метод, чтобы добавить любые данные из объекта запроса на ваш пользовательский класс валидации. Надеюсь, вы найдете это полезным!
Вы можете найти Пример репозитория на моем github Отказ
Эта статья очень вдохновлена идеей, которую я нашел в Этот комментарий на Github.
Придавать Это просто подтверждение концепции, и этот комментарий Validation является простым примером использования.
Оригинал: “https://dev.to/avantar/injecting-request-object-to-a-custom-validation-class-in-nestjs-5dal”