Skip to content

Validation

Request validation with @galaxy-stack/orbit-validation using Zod schemas.

ValidationPipe

typescript
import { BunFactory } from '@galaxy-stack/orbit-core';
import { ValidationPipe } from '@galaxy-stack/orbit-validation';

const app = await BunFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());

Zod Schema Validation

typescript
import { z } from 'zod';
import { ZodValidationPipe } from '@galaxy-stack/orbit-validation';

const createUserSchema = z.object({
  name: z.string().min(2).max(50),
  email: z.string().email(),
  age: z.number().int().min(18).optional(),
  role: z.enum(['user', 'admin']).default('user'),
});

type CreateUserDto = z.infer<typeof createUserSchema>;

@Controller('users')
export class UsersController {
  @Post()
  createUser(
    @Body(new ZodValidationPipe(createUserSchema)) data: CreateUserDto,
  ) {
    return this.usersService.create(data);
  }
}

Transform Decorators

typescript
import { Transform, Trim, ToLowerCase, ToNumber } from '@galaxy-stack/orbit-validation';

class SearchDto {
  @Trim()
  @ToLowerCase()
  query: string;

  @ToNumber()
  page: number;

  @Transform(({ value }) => value.split(','))
  tags: string[];
}

Custom Validators

typescript
const passwordSchema = z.string()
  .min(8)
  .regex(/[A-Z]/, 'Must contain uppercase')
  .regex(/[a-z]/, 'Must contain lowercase')
  .regex(/[0-9]/, 'Must contain number');

const registrationSchema = z.object({
  email: z.string().email(),
  password: passwordSchema,
  confirmPassword: z.string(),
}).refine(data => data.password === data.confirmPassword, {
  message: 'Passwords must match',
  path: ['confirmPassword'],
});

Error Response

json
{
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    {
      "field": "email",
      "message": "Invalid email format"
    },
    {
      "field": "age",
      "message": "Must be at least 18"
    }
  ]
}

Released under the MIT License.