Skip to main content
zerotal

Documentation


Documentation / zerotal / validator / FormRequest

Abstract Class: FormRequest

Defined in: packages/validator/src/FormRequest.ts:65

Base class for encapsulating validation rules and optional authorization in a reusable, testable class rather than inline in each handler.

Define rules via an instance rules(r) method. Because it is an instance method, you have full access to this.context inside your schema — enabling patterns like unique-except-current-user validation:

rules(r: RuleBuilder) {
  return {
    email: r.string().email().unique('users', 'email', this.context.user?.id),
    name:  r.string().min(2),
  };
}

Type inference: validate() uses ReturnType<T['rules']> to extract the narrow return type of the concrete subclass's rules() method. TypeScript evaluates this against the actual instantiated T at the call site — NOT the base class constraint — so the returned data is fully typed.

IMPORTANT: Do NOT add an explicit return type to your rules() override. Annotating it as Record<string, FieldRule> would widen the inferred type and cause validate() to return Record<string, unknown> instead.

Example

// app/requests/StorePostRequest.ts
export class StorePostRequest extends FormRequest {
  authorize() { return !!this.context.user; }

  rules(r: RuleBuilder) {
    return {
      title: r.string().min(3).max(255),
      body:  r.string().min(10),
    };
  }
}

// In a file-based route or controller:
const data = await StorePostRequest.validate();
// data.title → string  (fully typed — no casts needed)

Constructors

Constructor

new FormRequest(): FormRequest

Returns

FormRequest

Accessors

context

Get Signature

get protected context(): HttpContext

Defined in: packages/validator/src/FormRequest.ts:75

Access the current request's HttpContext from within instance methods. Pulled from AsyncLocalStorage — no constructor injection needed.

Example
authorize() {
  return !!this.context.user;
}
Returns

HttpContext

Methods

authorize()

authorize(): boolean | Promise<boolean>

Defined in: packages/validator/src/FormRequest.ts:89

Authorize the request before validation. Return true to allow (default), false to deny with 403. Access the current request via this.context.

Returns

boolean | Promise<boolean>

Example

authorize(): boolean {
  return !!this.context.user;
}

rules()

rules(_r): Record<string, FieldRule>

Defined in: packages/validator/src/FormRequest.ts:110

Define the validation rules for this request. Override in subclasses WITHOUT an explicit return type so TypeScript infers the narrow schema shape and validate() produces a fully-typed result.

You have full access to this.context inside this method — use it for rules that depend on the current user, route params, or session state.

Parameters

_r

RuleBuilder

Returns

Record<string, FieldRule>

Example

rules(r: RuleBuilder) {
  return {
    email: r.string().email().unique('users', 'email', this.context.user?.id),
    name:  r.string().min(2).max(100),
  };
}

macro()

static macro(name, fn): void

Defined in: packages/validator/src/FormRequest.ts:128

Attach a helper method to all FormRequest instances at runtime. Designed for framework packages (e.g. @zerotal/auth) that expose convenience methods like this.user() or this.auth().

Pair with a declaration merge on the exported FormRequest interface for TypeScript autocomplete on the added method.

Parameters

name

string

fn

(this, ...args) => unknown

Returns

void

Example

// In @zerotal/auth's provider:
FormRequest.macro('user', function(this: FormRequest) {
  return this.context.user;
});

validate()

static validate<T>(this): Promise<Infer<ExtractDefs<ReturnType<T["rules"]>>>>

Defined in: packages/validator/src/FormRequest.ts:149

Validate the HTTP request against this class's rules.

The return type is fully inferred from the concrete rules() override — no manual type assertions needed in the caller. TypeScript resolves ReturnType<T['rules']> against the actual T at the call site, not the base class constraint. HttpContext is pulled from per-request AsyncLocalStorage automatically (zero arguments).

On success: returns the validated, typed data object. On failure: throws ValidationRedirectError (Inertia / web form) or ValidationJsonError (JSON API), and stores errors in the session.

Type Parameters

T

T extends FormRequest

Parameters

this

() => T

Returns

Promise<Infer<ExtractDefs<ReturnType<T["rules"]>>>>

Example

const data = await StorePostRequest.validate();
data.title // string — not unknown