Skip to Content
Custom Decorators

Custom Decorators

A decorator adds behavior to a procedure. Use decorators for concerns that many procedures share, such as logging, caching, validation and authorization. They can also attach custom metadata, for example to identify the authorized user.

createDecorator makes a decorator factory: a function that returns a decorator for controller methods. It takes a middleware function with these parameters:

  • request, which extends VovkRequest. Its req.vovk.meta gets and sets metadata, to share data between decorators and the route handler.
  • next, a function that calls the next decorator or the route handler. Call it and return its result. To retry, call it again: each call validates the input as the client sent it.
  • The arguments passed to the decorator factory.

The optional second argument is an init handler. It runs each time the decorator is applied, and it can add validation or custom data to .vovk-schema/*.json. It returns an object with the optional keys "validation", "operationObject" and "misc" (custom metadata) to merge into the handler schema. Or it returns a function that gets the current handler schema and returns that object, so you merge them yourself.

import { createDecorator, get, HttpException, HttpStatus, type VovkRequest } from 'vovk'; export interface ReqMeta { foo: string; a: string; b: number; } const myDecorator = createDecorator( (req, next, a: string, b: number) => { console.log(a, b); // Outputs: "baz", 1 req.vovk.meta<ReqMeta>({ foo: 'bar', a, b }); // add metadata to the request if (isSomething) { // skip the handler and respond with { hello: 'world' } return { hello: 'world' }; } if (isSomethingElse) { // or throw an HTTP error throw new HttpException(HttpStatus.BAD_REQUEST, 'Something went wrong'); } // call the next decorator or the route handler return next(); }, (a: string, b: number) => { console.info('Decorator is initialized with', a, b); return { validation: { /* ... */ }, misc: { a, b }, // adds `a` and `b` to the handler schema }; } ); export default class MyController { @get.auto() @myDecorator('baz', 1) // Passes 'baz' as 'a' and 1 as 'b' static doSomething(req: VovkRequest) { const meta = req.vovk.meta<ReqMeta>(); console.log(meta); // { foo: 'bar', a: 'baz', b: 1 } // ... } }
Last updated on