Asosiy bo'lim4 min read

Maxsus route dekoratorlari

Nest dekoratorlar deb ataladigan til xususiyati atrofida qurilgan. Dekoratorlar ko'plab keng qo'llaniladigan dasturlash tillarida yaxshi tanish tushuncha, ammo JavaScript olamida u

Nest dekoratorlar deb ataladigan til xususiyati atrofida qurilgan. Dekoratorlar ko'plab keng qo'llaniladigan dasturlash tillarida yaxshi tanish tushuncha, ammo JavaScript olamida ular hali nisbatan yangi. Dekoratorlar qanday ishlashini yaxshiroq tushunish uchun ushbu maqolani o'qishni tavsiya qilamiz. Quyida sodda ta'rif keltirilgan:

ES2016 dekoratori funksiya qaytaradigan va target, name hamda property descriptorni argument sifatida qabul qiladigan ifodadir. Uni dekoratorni @ belgisi bilan oldindan qo'yib va dekoratsiya qilmoqchi bo'lgan narsaning eng yuqori qismiga joylashtirib qo'llaysiz. Dekoratorlar sinf, metod yoki xossa uchun aniqlanishi mumkin.

Param dekoratorlar

Nest HTTP route handlerlar bilan birga foydalanishingiz mumkin bo'lgan foydali param dekoratorlar to'plamini taqdim etadi. Quyida taqdim etilgan dekoratorlar va ular ifodalovchi oddiy Express (yoki Fastify) obyektlari ro'yxati keltirilgan.

@Request(), @Req()req
@Response(), @Res()res
@Next()next
@Session()req.session
@Param(param?: string)req.params / req.params[param]
@Body(param?: string)req.body / req.body[param]
@Query(param?: string)req.query / req.query[param]
@Headers(param?: string)req.headers / req.headers[param]
@Ip()req.ip
@HostParam()req.hosts

Bundan tashqari, siz o'zingizning maxsus dekoratorlaringizni ham yaratishingiz mumkin. Bu nima uchun foydali?

node.js dunyosida request obyektiga xossalarni biriktirish odatiy amaliyotdir. So'ng har bir route handlerda ularni quyidagi kabi kod bilan qo'lda ajratasiz:

TypeScript
1const user = req.user;

Kodingizni yanada o'qilishi oson va shaffof qilish uchun @User() dekoratorini yaratib, uni barcha controllerlaringiz bo'ylab qayta ishlatishingiz mumkin.

TypeScript
user.decorator
1import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2
3export const User = createParamDecorator(
4  (data: unknown, ctx: ExecutionContext) => {
5    const request = ctx.switchToHttp().getRequest();
6    return request.user;
7  },
8);

Keyin uni talablaringizga mos joylarda shunchaki ishlatasiz.

TypeScript
1@Get()
2async findOne(@User() user: UserEntity) {
3  console.log(user);
4}

Ma'lumot uzatish

Agar dekoratoringiz xatti-harakati qandaydir shartlarga bog'liq bo'lsa, data parametridan foydalanib dekoratorning factory funksiyasiga argument uzatishingiz mumkin. Buning bir foydalanish holati - request obyektidan kalit bo'yicha xossalarni ajratib oladigan maxsus dekorator. Masalan, authentication layer so'rovlarni tekshiradi va request obyektiga user entity ni biriktiradi, deb tasavvur qilaylik. Autentifikatsiyadan o'tgan so'rov uchun user entity quyidagicha ko'rinishi mumkin:

JSON
1{
2  "id": 101,
3  "firstName": "Alan",
4  "lastName": "Turing",
5  "email": "alan@email.com",
6  "roles": ["admin"]
7}

Keling, kalit sifatida xossa nomini qabul qilib, mavjud bo'lsa tegishli qiymatni (mavjud bo'lmasa yoki user obyekti yaratilmagan bo'lsa, undefined) qaytaradigan dekoratorni aniqlaylik.

TypeScript
user.decorator
1import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2
3export const User = createParamDecorator(
4  (data: string, ctx: ExecutionContext) => {
5    const request = ctx.switchToHttp().getRequest();
6    const user = request.user;
7
8    return data ? user?.[data] : user;
9  },
10);

So'ng controllerda @User() dekoratori orqali muayyan xossaga qanday kirishingiz mumkin:

TypeScript
1@Get()
2async findOne(@User('firstName') firstName: string) {
3  console.log(`Hello ${firstName}`);
4}

Siz shu dekoratordan turli kalitlar bilan foydalanib, turli xossalarga kirishingiz mumkin. Agar user obyekti chuqur yoki murakkab bo'lsa, bu request handler implementatsiyalarini yanada oson va o'qilishi qulay qiladi.

Hint

TypeScript foydalanuvchilari uchun eslatma: createParamDecorator<T>() generic hisoblanadi. Bu sizga tip xavfsizligini aniq belgilash imkonini beradi, masalan createParamDecorator<string>((data, ctx) => ...). Muqobil ravishda, factory funksiyasida parametr tipini ko'rsatishingiz mumkin, masalan createParamDecorator((data: string, ctx) => ...). Agar ikkalasini ham qoldirsangiz, data uchun tip any bo'ladi.

Pipe'lar bilan ishlash

Nest maxsus param dekoratorlarini o'rnatilganlari (@Body(), @Param() va @Query()) bilan bir xil tarzda ko'rib chiqadi. Bu pipe'lar maxsus anotatsiya qilingan parametrlarga ham qo'llanadi (bizning misollarda user argumenti). Bundan tashqari, pipe'ni to'g'ridan-to'g'ri maxsus dekoratorga qo'llashingiz mumkin:

TypeScript
1@Get()
2async findOne(
3  @User(new ValidationPipe({ validateCustomDecorators: true }))
4  user: UserEntity,
5) {
6  console.log(user);
7}
Hint

validateCustomDecorators opsiyasi true ga o'rnatilishi kerak. ValidationPipe odatda maxsus dekoratorlar bilan belgilangan argumentlarni validatsiya qilmaydi.

Dekoratorlar kompozitsiyasi

Nest bir nechta dekoratorlarni kompozitsiya qilish uchun yordamchi metod taqdim etadi. Masalan, autentifikatsiyaga oid barcha dekoratorlarni bitta dekoratorga birlashtirmoqchi bo'lsangiz. Buni quyidagi konstruktsiya bilan qilish mumkin:

TypeScript
auth.decorator
1import { applyDecorators } from '@nestjs/common';
2
3export function Auth(...roles: Role[]) {
4  return applyDecorators(
5    SetMetadata('roles', roles),
6    UseGuards(AuthGuard, RolesGuard),
7    ApiBearerAuth(),
8    ApiUnauthorizedResponse({ description: 'Unauthorized' }),
9  );
10}

Keyin ushbu maxsus @Auth() dekoratorini quyidagicha ishlatishingiz mumkin:

TypeScript
1@Get('users')
2@Auth('admin')
3findAllUsers() {}

Bu bitta deklaratsiya bilan to'rtta dekoratorning barchasi qo'llanishi bilan yakunlanadi.

Warning

@nestjs/swagger paketidagi @ApiHideProperty() dekoratori kompozitsiya qilinmaydi va applyDecorators funksiyasi bilan to'g'ri ishlamaydi.