NestJS Enterprise Backend APIs · Lektion

Dekoratoren auf Klassenebene für Querschnittskonfiguration

Kennzeichnen Sie Controller und Provider mit benutzerdefinierten Klassendekoratoren, um Feature-Flags und Mandantenbereiche zu steuern

Lektion 4 von 413 Schritte

Dekoratoren auf Klassenebene für Querschnittskonfiguration ist eine kostenlose NestJS Enterprise Backend APIs-Lektion auf CoddyKit. Dies ist Lektion 4 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.

Why Class-Level Decorators?

In an enterprise NestJS API, some configuration applies to a whole controller or provider, not a single route. Think feature flags, tenant scoping, audit categories, or rate-limit tiers.

  • Repeating this on every method is noisy and error-prone.
  • A class-level decorator lets you tag the class once and read that tag later.

The pattern: attach metadata to the class, then read it inside a guard, interceptor, or middleware to drive cross-cutting behavior.

Decorators Are Just Functions

A class decorator is a function that receives the class constructor as its only argument. You can wrap it in a factory so callers pass options.

Here is the raw shape, with no framework involved, so you can see exactly what runs at class-definition time.

// Plain TypeScript: a class decorator factory
function Tag(label: string) {
  return function (target: Function) {
    console.log(`Decorating ${target.name} with label=${label}`);
  };
}

@Tag('billing')
class InvoiceController {}

console.log('Class defined:', InvoiceController.name);

Storing Metadata with Reflect

Logging is not useful by itself. We need to store the config so other code can read it. NestJS builds on the reflect-metadata library, which lets you attach key/value metadata to a class.

  • Reflect.defineMetadata(key, value, target) writes.
  • Reflect.getMetadata(key, target) reads.

The class itself is the storage target, so the tag travels with the type.

A Tenant-Scope Decorator

Let's build a real one: @TenantScope('strict') marks a controller so that all its routes must resolve a tenant. We define a metadata key and a factory that writes it.

In NestJS you would normally use the built-in SetMetadata helper, but writing it by hand shows what it does under the hood.

import 'reflect-metadata';

export const TENANT_SCOPE = 'tenant:scope';

export function TenantScope(mode: 'strict' | 'optional') {
  return (target: Function) => {
    Reflect.defineMetadata(TENANT_SCOPE, mode, target);
  };
}

@TenantScope('strict')
class OrdersController {}

const mode = Reflect.getMetadata(TENANT_SCOPE, OrdersController);
console.log('Tenant mode:', mode); // strict

Using SetMetadata in NestJS

NestJS ships SetMetadata(key, value) which returns a decorator usable on both classes and methods. Wrapping it in a named factory gives you a clean, self-documenting API.

This is the idiomatic way to author custom decorators in NestJS instead of calling Reflect.defineMetadata yourself.

import { SetMetadata } from '@nestjs/common';

export const FEATURE_FLAG = 'feature:flag';

// Class-level decorator built on SetMetadata
export const FeatureFlag = (flag: string) =>
  SetMetadata(FEATURE_FLAG, flag);

@FeatureFlag('beta-checkout')
export class CheckoutController {}

Reading Metadata with Reflector

To consume the tag at request time, inject NestJS's Reflector service. A guard can read the class-level metadata from context.getClass().

  • reflector.get(KEY, context.getClass()) reads the controller-level tag.
  • reflector.getAllAndOverride(KEY, [handler, class]) lets a method override the class default.
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { FEATURE_FLAG } from './feature-flag.decorator';

@Injectable()
export class FeatureFlagGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const flag = this.reflector.get<string>(
      FEATURE_FLAG,
      context.getClass(),
    );
    if (!flag) return true; // no flag => always allowed
    return isFeatureEnabled(flag);
  }
}

declare function isFeatureEnabled(flag: string): boolean;

Method Overrides Class

A common enterprise need: the controller sets a default, but one route opts out. getAllAndOverride checks the handler first, then falls back to the class.

Order matters: the array is searched left to right, so put the most specific target (the method handler) first.

canActivate(context: ExecutionContext): boolean {
  const mode = this.reflector.getAllAndOverride<'strict' | 'optional'>(
    TENANT_SCOPE,
    [context.getHandler(), context.getClass()],
  );
  // method @TenantScope('optional') wins over class @TenantScope('strict')
  return mode === 'optional' ? true : this.hasTenant(context);
}

Composing Multiple Tags

Cross-cutting config often combines concerns: a feature flag and a tenant mode and an audit category. Use applyDecorators to bundle them into one expressive decorator.

This keeps controllers readable: one decorator communicates the full intent.

import { applyDecorators, SetMetadata } from '@nestjs/common';
import { FEATURE_FLAG } from './feature-flag.decorator';
import { TENANT_SCOPE } from './tenant-scope.decorator';
import { AUDIT_CATEGORY } from './audit.decorator';

export function EnterpriseModule(opts: {
  flag: string;
  tenant: 'strict' | 'optional';
  audit: string;
}) {
  return applyDecorators(
    SetMetadata(FEATURE_FLAG, opts.flag),
    SetMetadata(TENANT_SCOPE, opts.tenant),
    SetMetadata(AUDIT_CATEGORY, opts.audit),
  );
}

@EnterpriseModule({ flag: 'beta-checkout', tenant: 'strict', audit: 'orders' })
export class OrdersController {}

Tagging Providers, Not Just Controllers

Class-level decorators are not limited to controllers. You can tag any provider class and read the metadata wherever you have the class reference, for example in a factory or a discovery service.

NestJS's DiscoveryService can enumerate all providers and inspect their metadata, which is how you build registries of tagged services.

import 'reflect-metadata';

const CACHE_TIER = 'cache:tier';
function CacheTier(tier: 'hot' | 'cold') {
  return (target: Function) => Reflect.defineMetadata(CACHE_TIER, tier, target);
}

@CacheTier('hot')
class PricingService {}

@CacheTier('cold')
class ReportService {}

for (const svc of [PricingService, ReportService]) {
  const tier = Reflect.getMetadata(CACHE_TIER, svc);
  console.log(`${svc.name} -> ${tier}`);
}

Wiring the Guard Globally

For cross-cutting config to take effect everywhere, register the consuming guard or interceptor once at the module level. The guard then inspects each request's target class.

A global guard plus class-level metadata means you configure behavior declaratively on each controller, with zero per-route wiring.

import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { FeatureFlagGuard } from './feature-flag.guard';

@Module({
  providers: [
    { provide: APP_GUARD, useClass: FeatureFlagGuard },
  ],
})
export class AppModule {}

Typing Metadata Keys Safely

Stringly-typed keys ('tenant:scope') are easy to mistype. Two safeguards used in enterprise codebases:

  • Export the key as a const from the decorator file so producer and consumer share one symbol.
  • Make the factory's argument a union type so invalid modes fail at compile time.

This turns config typos into TypeScript errors instead of silent runtime bugs.

type TenantMode = 'strict' | 'optional';

function validate(mode: TenantMode): TenantMode {
  return mode;
}

console.log(validate('strict'));
// validate('loose') would be a compile-time error
console.log('Allowed modes: strict | optional');

Quick Check

A controller is tagged @TenantScope('strict') at the class level, and one of its methods is tagged @TenantScope('optional'). Your guard must let that method opt out while keeping the strict default for the rest.

Recap

You learned how to drive cross-cutting config with class-level decorators:

  • Author a decorator with SetMetadata (or Reflect.defineMetadata) wrapped in a typed factory.
  • Consume the tag with Reflector from context.getClass() inside a guard or interceptor.
  • Override class defaults per-method using getAllAndOverride with the handler listed first.
  • Compose multiple concerns via applyDecorators, and tag providers too, not just controllers.
  • Register the consumer globally with APP_GUARD so the config applies declaratively across the app.

The result: feature flags and tenant scoping configured once per class, enforced everywhere.

Kostenlos starten

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 auf Klassenebene für Querschnittskonfiguration“ kostenlos?

Ja — der vollständige Text von „Dekoratoren auf Klassenebene für Querschnittskonfiguration“ 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 auf Klassenebene für Querschnittskonfiguration“?

Kennzeichnen Sie Controller und Provider mit benutzerdefinierten Klassendekoratoren, um Feature-Flags und Mandantenbereiche zu steuern 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 4 von 4.

Wie lange dauert die Lektion „Dekoratoren auf Klassenebene für Querschnittskonfiguration“?

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

  1. Request-Context mit Param-Dekoratoren auslesen
  2. Metadaten mit SetMetadata und Reflector anhängen
  3. Dekoratoren mit applyDecorators kombinieren
  4. Dekoratoren auf Klassenebene für Querschnittskonfiguration
← Zurück zu NestJS Enterprise Backend APIs