Runtime Validation
TypeScript types disappear at runtime. A type assertion like data as Product[] doesn’t actually check anything — it just tells the compiler to stop complaining.
WELD uses Zod schemas at the network boundary to validate that what the server actually sends matches the contract you defined. If it doesn’t, WELD throws a WeldValidationError before the data reaches your UI.
Basic usage
Section titled “Basic usage”import { z } from 'zod'
const ProductSchema = z.object({ id: z.string(), name: z.string(), price: z.number().positive(),})
const { promise } = api.get('v1/products', z.array(ProductSchema))
// If the server sends { id: 1 } (number instead of string),// WELD throws WeldValidationError — your UI never sees bad dataZero-config mode
Section titled “Zero-config mode”Schema is always optional. Without one, WELD returns the raw response:
// No schema — returns unknown, no validationconst { promise } = api.get('v1/products')const data = await promise // type: unknownThis is the right choice for quick prototypes or when you trust the API completely.
Handling validation errors
Section titled “Handling validation errors”import { WeldValidationError } from 'weld-http'
try { const products = await api.get('v1/products', z.array(ProductSchema)).promise} catch (err) { if (err instanceof WeldValidationError) { console.error('API response did not match schema:', err.issues) }}With signals:
const { signal } = api.get('v1/products', z.array(ProductSchema))
signal.error.subscribe((err) => { if (err instanceof WeldValidationError) { // Show validation error UI }})Zod transforms
Section titled “Zod transforms”Zod schemas can transform data as they validate it. WELD applies transforms automatically:
const ProductSchema = z.object({ id: z.string(), name: z.string().trim(), price: z.number(), // Parse ISO string into Date object created_at: z.string().transform((s) => new Date(s)),})
const { promise } = api.get('v1/products', z.array(ProductSchema))const products = await promise// products[0].created_at is a Date, not a stringWhere validation fits in the pipeline
Section titled “Where validation fits in the pipeline”Validation always runs after the network response is received and before the data reaches your signals or promise. This means:
- Your UI only ever receives valid, typed data
- Validation errors are treated exactly like network errors — they set
status = 'error'and populatesignal.error
