Skip to Content
Decorator Examples

Decorator Examples

console.log Decorator

This decorator logs the request method and URL, then calls the next decorator or the route handler.

src/decorators/log.ts
import { createDecorator } from 'vovk'; const log = createDecorator((req, next, message?: string) => { console.log(`${message ?? 'Incoming request'}: ${req.method} ${req.url}`); return next(); }); export default log;

Import log and apply it to a procedure below the HTTP decorator (@get, @post and so on).

src/modules/user/user-controller.ts
import { get, prefix } from 'vovk'; import log from '../../decorators/log'; @prefix('users') export default class UserController { @get('info') @log('Fetching user info') static async getUserInfo() { // ... } }

Basic Authorization Decorator

With Basic authentication, the client sends the username and password in the Authorization header, encoded in Base64. It is not the most secure method, but it can be useful between older services.

src/decorators/basic-auth-guard.ts
import { HttpException, HttpStatus, createDecorator } from 'vovk'; const basicAuthGuard = createDecorator((req, next) => { const authorisation = req.headers.get('authorization'); if (!authorisation) { throw new HttpException(HttpStatus.UNAUTHORIZED, 'No authorisation header'); } const token = authorisation.split(' ')[1]; if (!token) { throw new HttpException(HttpStatus.UNAUTHORIZED, 'No token provided'); } let login, password; try { [login, password] = Buffer.from(token, 'base64').toString().split(':'); } catch (error) { throw new HttpException(HttpStatus.UNAUTHORIZED, 'Unable to parse token. ' + String(error)); } if (login !== process.env.BASIC_AUTH_LOGIN || password !== process.env.BASIC_AUTH_PASSWORD) { throw new HttpException(HttpStatus.UNAUTHORIZED, 'Invalid login or password'); } return next(); }); export default basicAuthGuard;

Apply basicAuthGuard to procedures below the HTTP decorator.

src/modules/secure/secure-controller.ts
import { get, prefix } from 'vovk'; import basicAuthGuard from '../../decorators/basic-auth-guard'; @prefix('secure') export default class SecureController { @get('data') @basicAuthGuard() static async getSecureData() { // ... } }

RBAC Decorator

Role-based access control (RBAC) limits what users can do by their role in an organization, instead of by permissions given to each user.

The authGuard decorator below:

  • Checks that the user is authorized, and otherwise responds with the Unauthorized status.
  • Adds currentUser to the request metadata, typed by the AuthMeta interface.
  • Checks the role with the Permission enum.

identifyUserAndCheckPermissions stands for your code that finds the user from the request (for example, from a JWT or a session) and checks that they have the permission.

src/decorators/auth-guard.ts
import { createDecorator, HttpException, HttpStatus, type VovkRequest } from 'vovk'; import type { User } from '@/types'; export enum Permission { CAN_DO_THIS = 'CAN_DO_THIS', CAN_DO_THAT = 'CAN_DO_THAT', } // lets the controller read currentUser from the metadata export interface AuthMeta { currentUser: User; } // identify the user, check the permission and set the request metadata const checkAuth = async (req: VovkRequest, permission: Permission) => { const currentUser = identifyUserAndCheckPermissions(req, permission); if (!currentUser) { return false; } // Add currentUser to the request metadata req.vovk.meta<AuthMeta>({ currentUser }); return true; }; // Create the decorator const authGuard = createDecorator(async (req, next, permission: Permission) => { const isAuthorized = await checkAuth(req, permission); if (!isAuthorized) { throw new HttpException(HttpStatus.UNAUTHORIZED, 'Unauthorized'); } // authorized, with the metadata set: call the next decorator or the handler return next(); }); export default authGuard;

Import authGuard with Permission and AuthMeta, then apply it to procedures below the HTTP decorator.

src/modules/user/user-controller.ts
import { get, prefix, type VovkRequest } from 'vovk'; import authGuard, { Permission, type AuthMeta } from '../../decorators/auth-guard'; @prefix('users') export default class UserController { // ... @get('something') @authGuard(Permission.CAN_DO_THIS) static async getSomething(req: VovkRequest) { const { currentUser } = req.vovk.meta<AuthMeta>(); // ... } // ... }

Vercel Cron Jobs Authorization Decorator

Vercel Cron Jobs  authorize with a secret in an environment variable. A decorator can check the Authorization header against it.

src/decorators/cron-guard.ts
import { HttpException, HttpStatus, createDecorator } from 'vovk'; const cronGuard = createDecorator(async (req, next) => { if (req.headers.get('authorization') !== `Bearer ${process.env.CRON_SECRET}`) { throw new HttpException(HttpStatus.UNAUTHORIZED, 'Unauthorized'); } return next(); }); export default cronGuard;

Apply cronGuard to the procedure the cron job calls.

src/modules/cron/cron-controller.ts
import { get, prefix } from 'vovk'; import cronGuard from '../../decorators/cron-guard'; @prefix('cron') export default class CronController { @get('do-something') @cronGuard() static async doSomething() { // ... } }

Add the cron job to vercel.json. The schedule field uses standard cron syntax; this one runs every day at midnight.

/vercel.json
{ "crons": [ { "path": "/api/cron/do-something", "schedule": "0 0 * * *" } ] }
Last updated on