Creating Validators

Validation can be often be tricky or inconsistent to implement.

We can leverage an interface to bind the shape of our request and then have it implemented through a class. We can use the class-validator libary to achieve this.


Assumptions

  • A clean or monorepo Enso installation
  • A UsersController controller that has been wired to your container

Example

We will use the example of validating a RegisterUserRequest

Define our interface

// file: src/users/interfaces.ts

export interface IRegisterUserRequest {
  firstName: string
  lastName: string
  email: string
}

Implement our interface

And annnotate our class with some validation rules. Be sure to explore the available validation decorators and docs.

// file: src/users/requests.ts
import { IRegisterUserRequest } from './interfaces'

export class RegisterUserRequest implements IRegisterUserRequest {

  @IsNotEmpty()  firstName: string

  @IsNotEmpty()  lastName: string

  @IsNotEmpty()  @IsEmail()  email: string
}

Implement the Validator on our endpoint

We can use the documented example or enhance our code with some middleware.

Create the middleware

// file: src/vendor/class-validator/middleware.ts

import { Middleware } from 'koa'
import { transformAndValidate, ClassType } from 'class-transformer-validator'

/**
 * - Runs transformAndValidate() as middleware
 * - Patches koa [ctx.data] with validated [ctx.request.body]
 *
 * Usage:
 *    @httpPost('/path', validate(Class))
 */
export function validate<T extends object>(classType: ClassType<T>): Middleware{
  return async (ctx, next) => {
    ctx.data = await transformAndValidate(classType, ctx.request.body)
    await next()
  }
}

Implement our Validator as middleware

import { validate } from '../../vendor/class-validator/middleware'

@injectable()
@controller('/users')
export class UsersController implements interfaces.Controller {

  /**
   * POST /users/register
   */
  @httpPost('/register', validate(RegisterUserRequest))
  async registerUser (ctx: Router.IRouterContext) {

    // make javascript great again

    ctx.status = 201
  }

}

💯

Notes