Dekoratoren mit applyDecorators kombinieren
Bündeln Sie Swagger-, Validierungs- und Auth-Dekoratoren in einem einzigen ergonomischen @ApiSecureEndpoint-Dekorator
Dekoratoren mit applyDecorators kombinieren ist eine kostenlose NestJS Enterprise Backend APIs-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des NestJS Enterprise Backend APIs-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der NestJS Enterprise Backend APIs-Kurs umfasst insgesamt 4 Lektionen.
Teile dieser Lektion wurden noch nicht übersetzt und werden auf Englisch angezeigt.
The Decorator Stacking Problem
In a real NestJS enterprise API, almost every route handler ends up carrying a tall stack of decorators: Swagger docs, auth guards, role checks, and response shaping. Repeating that stack on every endpoint is verbose and error-prone.
- Duplication: the same six lines copied onto dozens of handlers.
- Drift: someone forgets
@ApiBearerAuth()on one route and the docs lie. - Noise: the actual business intent is buried under cross-cutting concerns.
This lesson teaches how to collapse a recurring decorator stack into a single reusable @ApiSecureEndpoint() using NestJS's applyDecorators.
// The pain: this stack repeats on every secured route
@Post('transfer')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
@ApiOperation({ summary: 'Move funds between accounts' })
@ApiOkResponse({ description: 'Transfer accepted' })
@ApiUnauthorizedResponse({ description: 'Missing or invalid token' })
async transfer(@Body() dto: TransferDto) {
return this.bank.transfer(dto);
}What applyDecorators Actually Does
applyDecorators is a helper from @nestjs/common. It takes any number of decorators and returns one new decorator that applies all of them in order when used.
- It works with method decorators, class decorators, and property decorators.
- The decorators run top-to-bottom, exactly as if you had written them by hand.
- It does not change behavior — it only composes. Whatever the original stack did, the composed decorator does identically.
Think of it as function composition for the decorator world.
import { applyDecorators, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
export function SecureRoute() {
return applyDecorators(
UseGuards(JwtAuthGuard),
ApiBearerAuth(),
ApiOperation({ summary: 'Protected route' }),
);
}A Custom Decorator Is Just a Function
Before composing, recall the shape of a custom decorator. A method decorator is a function that receives the target, the property key, and the property descriptor. NestJS decorators like UseGuards() are decorator factories: calling them returns such a function.
This plain-TypeScript example shows the mechanics with no framework involved — a logging decorator factory applied to a class method.
function LogCalls(label: string) {
return function (
_target: object,
key: string,
descriptor: PropertyDescriptor,
) {
const original = descriptor.value;
descriptor.value = function (...args: unknown[]) {
console.log(`[${label}] ${key} called`);
return original.apply(this, args);
};
};
}
class Calculator {
@LogCalls('math')
add(a: number, b: number): number {
return a + b;
}
}
const c = new Calculator();
console.log('result =', c.add(2, 3));Composing Without a Helper
To appreciate applyDecorators, see what manual composition looks like in pure TypeScript. A composer returns a single method decorator that loops over the inner decorators and invokes each.
This standalone snippet mirrors how NestJS's applyDecorators works under the hood — running every decorator against the same target.
type MethodDec = (t: object, k: string, d: PropertyDescriptor) => void;
function compose(...decorators: MethodDec[]): MethodDec {
return (target, key, descriptor) => {
for (const dec of decorators) {
dec(target, key, descriptor);
}
};
}
const tag = (name: string): MethodDec => (_t, k) =>
console.log(`applied ${name} to ${k}`);
class Service {
@compose(tag('auth'), tag('swagger'), tag('roles'))
handle(): string {
return 'ok';
}
}
console.log(new Service().handle());Building the First Version of @ApiSecureEndpoint
Now bundle the realistic stack. Our goal decorator @ApiSecureEndpoint() should attach JWT auth, role enforcement, the Swagger bearer scheme, and the common error responses.
UseGuardswires the runtime protection.ApiBearerAuthtells Swagger UI to send the token.- The
ApiUnauthorizedResponse/ApiForbiddenResponsedocument the failure modes once and for all.
import { applyDecorators, UseGuards } from '@nestjs/common';
import {
ApiBearerAuth,
ApiUnauthorizedResponse,
ApiForbiddenResponse,
} from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { RolesGuard } from '../auth/roles.guard';
export function ApiSecureEndpoint() {
return applyDecorators(
UseGuards(JwtAuthGuard, RolesGuard),
ApiBearerAuth(),
ApiUnauthorizedResponse({ description: 'Missing or invalid token' }),
ApiForbiddenResponse({ description: 'Insufficient permissions' }),
);
}Using the Composed Decorator
With the composer in place, the controller collapses to a single intent-revealing line per route. The four concerns are still active — they are just declared once inside the factory.
Compare this to scene 1: the same protection and documentation, far less noise.
@Controller('accounts')
export class AccountsController {
constructor(private readonly bank: BankService) {}
@Post('transfer')
@ApiSecureEndpoint()
@ApiOperation({ summary: 'Move funds between accounts' })
async transfer(@Body() dto: TransferDto) {
return this.bank.transfer(dto);
}
}Passing Arguments Into the Composer
The real ergonomic win comes from parameterizing the factory. Because ApiSecureEndpoint is a function, it can accept options and forward them to the inner decorators — for example the required roles and a summary string.
This lets one decorator express the full security + docs contract of a route in a single, readable call.
import { applyDecorators, UseGuards, SetMetadata } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiForbiddenResponse } from '@nestjs/swagger';
export const ROLES_KEY = 'roles';
export function ApiSecureEndpoint(opts: { summary: string; roles?: string[] }) {
return applyDecorators(
UseGuards(JwtAuthGuard, RolesGuard),
SetMetadata(ROLES_KEY, opts.roles ?? []),
ApiBearerAuth(),
ApiOperation({ summary: opts.summary }),
ApiForbiddenResponse({ description: 'Insufficient permissions' }),
);
}Folding in Validation and Response Typing
Enterprise endpoints also document their success payload. applyDecorators can fold in a typed ApiOkResponse, and you can combine it with a serialization interceptor so the contract is enforced both in code and in the docs.
typedrives the Swagger response schema and example.- Adding
UseInterceptors(ClassSerializerInterceptor)guarantees the DTO transforms apply.
import { applyDecorators, UseGuards, UseInterceptors, ClassSerializerInterceptor, Type } from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiOperation } from '@nestjs/swagger';
export function ApiSecureEndpoint(opts: {
summary: string;
type: Type<unknown>;
}) {
return applyDecorators(
UseGuards(JwtAuthGuard, RolesGuard),
UseInterceptors(ClassSerializerInterceptor),
ApiBearerAuth(),
ApiOperation({ summary: opts.summary }),
ApiOkResponse({ type: opts.type, description: 'Success' }),
);
}Order Matters for Guards and Interceptors
Within a composed decorator, the relative order of UseGuards and UseInterceptors matters at runtime. NestJS runs guards before interceptors regardless, but when you list multiple guards their execution order follows the array, and multiple interceptors nest in declaration order.
- Put authentication guards before authorization guards so an unauthenticated request short-circuits with 401, not 403.
- Swagger-only decorators (
ApiOperation,ApiOkResponse) have no runtime ordering effect — they only attach metadata.
// JwtAuthGuard first => 401 before RolesGuard ever runs => correct
UseGuards(JwtAuthGuard, RolesGuard)
// Reversed => RolesGuard may read an empty user and throw 403
// for a request that was actually just unauthenticated
UseGuards(RolesGuard, JwtAuthGuard) // avoidKeeping the Decorator Testable
Because a composed decorator is a plain factory function, you can unit-test that it wires the metadata you expect without booting Nest. Use the Reflector or read metadata keys directly off the decorated method.
This standalone TypeScript example demonstrates the underlying idea — reading back metadata that a decorator attached via Reflect.defineMetadata.
import 'reflect-metadata';
function Roles(...roles: string[]) {
return (t: object, k: string) =>
Reflect.defineMetadata('roles', roles, t, k);
}
class Ctrl {
@Roles('admin', 'auditor')
remove() {}
}
const meta = Reflect.getMetadata('roles', Ctrl.prototype, 'remove');
console.log('declared roles =', meta);
console.log('admin allowed =', meta.includes('admin'));When NOT to Compose
Composition is powerful but can hide important details. Reach for a composed decorator only when the stack is genuinely repeated and stable.
- Do compose a fixed security + docs envelope used across many routes.
- Avoid composing highly route-specific details like a unique
ApiOperationsummary or one-off query params — pass those as arguments or leave them inline. - Avoid burying rarely-used behavior; a reader should still grasp what a route does from its decorators.
Good composed decorators reduce noise without becoming a black box.
Quick Check: Composing Decorators
You want a single @ApiSecureEndpoint() that applies a JWT guard, a roles guard, the Swagger bearer scheme, and shared error responses. Which approach is idiomatic in NestJS?
Recap & Takeaways
You learned to collapse a repetitive decorator stack into one ergonomic decorator.
applyDecoratorsfrom@nestjs/commoncomposes any number of decorators into a single one that applies them in order.- A composed decorator is just a factory function, so it can accept options (roles, summary, response type) and forward them to the inner decorators.
- Bundle stable cross-cutting concerns —
UseGuards,ApiBearerAuth, sharedApiUnauthorizedResponse/ApiForbiddenResponse— and keep route-specific details as arguments or inline. - Mind guard ordering: authentication before authorization so a missing token yields 401, not 403.
- Because it is plain TypeScript, the composed decorator stays testable via reflected metadata.
Result: controllers that read as intent (@ApiSecureEndpoint({ summary, roles })) instead of a wall of boilerplate.
Lerne TypeScript mit einem KI-Tutor — kostenlos
Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.
- Kurse
- 20
- Lektionen
- 76
Häufig gestellte Fragen
Ist die Lektion „Dekoratoren mit applyDecorators kombinieren“ kostenlos?
Ja — der vollständige Text von „Dekoratoren mit applyDecorators kombinieren“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des NestJS Enterprise Backend APIs-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der NestJS Enterprise Backend APIs-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Dekoratoren mit applyDecorators kombinieren“?
Bündeln Sie Swagger-, Validierungs- und Auth-Dekoratoren in einem einzigen ergonomischen @ApiSecureEndpoint-Dekorator Du übst NestJS Enterprise Backend APIs mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um NestJS Enterprise Backend APIs zu starten?
Keine Vorkenntnisse erforderlich. NestJS Enterprise Backend APIs auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Dekoratoren mit applyDecorators kombinieren“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser NestJS Enterprise Backend APIs-Lektion Code schreiben und ausführen?
Ja. Jede NestJS Enterprise Backend APIs-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Request-Context mit Param-Dekoratoren auslesen
- Metadaten mit SetMetadata und Reflector anhängen
- Dekoratoren mit applyDecorators kombinieren
- Dekoratoren auf Klassenebene für Querschnittskonfiguration