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 providesreq.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 }
// ...
}
}