Skip to Content
ControllerDecorators

Decorators

The purpose of controller decorators is to provide a way to extend the functionality of controller methods. They can be used to implement cross-cutting concerns, such as logging, caching, validation, and authorization. They also allow to add custom metadata to the handler, which can be used for various purposes, such as identifying authorized users.

createDecorator is a higher-order function that produces a decorator factory (a function that returns a decorator) for controller class methods. It accepts a middleware function with the following parameters:

  • request, which extends VovkRequest. It provides req.vovk.meta method to get and set metadata for the request object to share data between decorators and the route handler.
  • next, a function that should be invoked and its result returned to call subsequent decorators or the route handler.
  • … additional arguments are passed through to the decorator factory.

The second argument of createDecorator is an optional init handler. It’s called every time when decorator is initialised and it’s purpose is to populate .vovk-schema/*.json with validation or custom data. It can return an object with optional keys "validation", "openapi" and "misc" that will be merged with the handler schema, or a function that returns the object and receives the existing handler schema as an argument for proper merging.

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