Validation at the Boundary
Critical rules
- Validate untrusted input once at the edge (HTTP, CLI, queue, env, third-party). Everything inside trusts types by contract.
- Parse into richer types (Zod + branded types) — don't just boolean-check.
- Business functions contain no shape/format checks on
args. - Schema failures →
VALIDATION_FAILED/ HTTP 400. Business-rule failures → Results (result-types). - Always parse third-party responses before use.
- Before schemas or branding choices, read references/examples.md and references/patterns.md.
Workflow
- Identify every untrusted entry point for the feature.
- Define Zod schemas; brand IDs/tokens that could be swapped by mistake.
- Parse at the boundary (
safeParse/ middleware). Reject with a standard error envelope. - Pass inferred types into
fn(args, deps)with no re-validation. - Keep domain rules (permissions, balances) inside business functions as Results.
- For coercion, PATCH, transforms, and middleware, read references/patterns.md.
Resources
- references/examples.md — parse mindset, branded types, handlers, error format. Read when implementing boundaries.
- references/patterns.md — two layers, coercion, PATCH, middleware, rationalizations. Read for common patterns.
Validation
- Every external input parsed with Zod at the boundary
- Business functions accept validated types; no shape checks inside
- Confusable IDs/tokens use branded types
- Third-party responses parsed before use
- Invalid input → consistent
VALIDATION_FAILED/ 400 - Business-rule failures returned as Results
- No re-validation of internal or DB-sourced data
Constraints
- Do not validate between internal functions that already share a type contract.
- Related:
fn-args-deps,result-types,api-design,strict-typescript,config-management.