🚧 AvleonJs is in active development and not ready for production use.

Validation

Validating request bodies and query strings with DTOs.

Avleon validates request input with class-validator DTOs. Annotate a class, use it as the type of a @Body() or @Query() parameter, and validation runs automatically before your handler.

class-validator and class-transformer ship with @avleon/core.

Defining a DTO

dtos/create-user.dto.ts
import { IsString, IsInt, IsEmail, IsOptional, Min, Max } from 'class-validator';

export class CreateUserDto {
  @IsString()
  name: string;

  @IsEmail()
  email: string;

  @IsInt()
  @Min(18)
  @Max(120)
  age: number;

  @IsOptional()
  @IsString()
  bio?: string;
}

Validating the body

Type the @Body() parameter with the DTO — that is all that is needed:

controllers/users.controller.ts
import { ApiController, Post, Body } from '@avleon/core';
import { CreateUserDto } from '../dtos/create-user.dto';

@ApiController('/users')
export class UsersController {
  @Post()
  create(@Body() body: CreateUserDto) {
    // body is validated and transformed into a CreateUserDto
    return body;
  }
}

When validation fails the request is rejected with 400 before the handler runs:

{
  "code": 400,
  "error": "ValidationError",
  "errors": [
    {
      "path": "email",
      "constraints": { "isEmail": "email must be an email" }
    }
  ]
}

Validating the query string

The same applies to @Query():

export class ListUsersDto {
  @IsOptional()
  @IsInt()
  @Min(1)
  page?: number;
}

@Get()
index(@Query() query: ListUsersDto) {
  return { page: query.page ?? 1 };
}

Deriving DTOs

Rather than repeating fields, derive one DTO from another. The validation rules come along with the properties.

HelperResult
PartialType(Dto)Every property optional — ideal for updates
PickType(Dto, ['a', 'b'])Only the named properties
OmitType(Dto, ['a'])Everything except the named properties
dtos/update-user.dto.ts
import { PartialType } from '@avleon/core';
import { CreateUserDto } from './create-user.dto';

export class UpdateUserDto extends PartialType(CreateUserDto) {}
import { PickType, OmitType } from '@avleon/core';

export class UserCredentialsDto extends PickType(CreateUserDto, ['email']) {}
export class PublicUserDto extends OmitType(CreateUserDto, ['email']) {}

Extra validators

Avleon adds validators on top of the class-validator set:

import { IsArrayNotEmpty } from '@avleon/core';

export class CreateOrderDto {
  @IsArrayNotEmpty({ message: 'An order needs at least one item' })
  items: number[];
}

Validating by hand

For input that does not come from a DTO, validateOrThrow checks a plain object against a rule map and throws a BadRequestException on failure:

import { validateOrThrow } from '@avleon/core';

validateOrThrow(
  { page: 1 },
  { page: { type: 'number', min: 1, required: true } },
);

Supported rule types are string, number (with min, max, exact) and boolean, each accepting required, optional and a custom message.