bootgs-validation

Documents bootgs' parameter-level validation decorators (@Min, @Max, @Email, @Pattern, @Size, @NotBlank, @NotEmpty, @AssertTrue, @AssertFalse, @Positive, @PositiveOrZero, @Negative, @NegativeOrZero),

SKILL.md

GitHub

Bootgs Validation

Available files

  • references/decorators-and-pipes.md — full list of validation decorators and Parse pipes. Load it when you need to check whether a specific constraint exists or what a pipe coerces to; the pattern for using them is below.

Model

bootgs validates individual parameters, not whole DTO classes — there is no class-validator-style @ValidateNested/decorated-DTO pipeline. A validation decorator stacks on top of an extraction decorator (@Query, @Param, @Body) and runs against the already-extracted value before the handler body executes:

@Get()
findAll(
  @Query("page") @Min(1) page: number,
  @Query("limit") @Max(100) limit: number,
) { /* page and limit are guaranteed valid here */ }

Multiple validators stack freely on one parameter; each runs in decorator-application order. The available decorators — @Min, @Max, @Email, @Pattern, @Size, @NotBlank, @NotEmpty, @AssertTrue/@AssertFalse, @Positive/@PositiveOrZero, @Negative/@NegativeOrZero — are listed with their exact checks in references/decorators-and-pipes.md.

Parse pipes (extraction-time coercion)

GAS delivers every parameter as a string. Use a Parse pipe as the second argument to @Param/@Query to coerce it before your handler sees it — don't hand-parse Number(value) in the handler body:

@Get("{id}")
findOne(@Param("id", ParseNumberPipe) id: number) { /* id is a number, not "42" */ }

Six are available (ParseIntPipe, ParseFloatPipe, ParseBigIntPipe, ParseBooleanPipe, ParseNumberPipe, ParseStringPipe) — see references/decorators-and-pipes.md for what each coerces to.

Custom pipes

import { PipeTransform, ArgumentMetadata, UsePipes } from "bootgs";

class TrimPipe implements PipeTransform<string, string> {
  transform(value: string, metadata: ArgumentMetadata): string {
    return value.trim();
  }
}

@UsePipes(TrimPipe)
@Post()
create(@Body("name") name: string) { /* name is trimmed */ }

@UsePipes applies at the class or method level and accepts multiple pipes, run in order.

Gotcha: validation failures throw a bare Error, not HttpException

Every built-in validation decorator throws new Error("Validation failed (...)") on failure — not AppException/HttpException. If your @ControllerAdvice/@ExceptionHandler only catches AppException, a validation failure falls through as an unhandled 500 instead of a clean 400. Handle it explicitly:

@ControllerAdvice()
class GlobalExceptionHandler {
  @ExceptionHandler(Error)
  handleValidation(err: Error) {
    return ResponseEntity.badRequest().body({ message: err.message });
  }
}

Order @ExceptionHandler registrations from most-specific to least-specific (AppException before the generic Error catch-all) if you need different status codes for domain exceptions versus validation failures.

Verification

For each validation decorator you add, write one test that calls the handler with a value that should fail and assert the response status/message — a decorator with no corresponding negative test is unverified surface area, since bootgs doesn't type-check the constraint against the parameter's type at compile time (e.g. @Email() on a number parameter compiles fine and fails at runtime).