Skip to main content

Runtime validation with Zod

Use case

Validate API responses at runtime against a Zod schema, getting both type safety and runtime guarantees.

Smallest working example

import { createClient } from '@parcely/core'
import { z } from 'zod'

const http = createClient({ baseURL: 'https://api.example.com' })

const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
})

const { data } = await http.get('/users/me', {
validate: UserSchema,
})
// data is typed as { id: string; name: string; email: string }

How it works

parcely accepts any Standard Schema v1 validator in the validate option. Zod 3.24+ implements Standard Schema, so schemas work out of the box with no adapter.

When validation fails, parcely throws HttpError with:

  • code: 'ERR_VALIDATION'
  • response: the original response envelope
  • cause: the validation error from Zod

Error handling

import { isHttpError } from '@parcely/core'

try {
await http.get('/users/me', { validate: UserSchema })
} catch (err) {
if (isHttpError(err) && err.code === 'ERR_VALIDATION') {
console.log('Validation failed:', err.cause)
console.log('Raw response:', err.response?.data)
}
}

Axios equivalent

Axios does not have built-in validation. Libraries like axios-zod add it. In parcely, it is a first-class feature.

Notes and gotchas

  • Zod is a dev/runtime dependency of your app, not of parcely. parcely has zero runtime dependencies.
  • Validation runs after the response body is parsed and before the response envelope is returned.
  • The Validator<T> type accepts Standard Schema v1 objects, { parse(input: unknown): T } objects, or (input: unknown) => T functions.
  • For Zod versions before 3.24 (no Standard Schema), the .parse() method shape is also supported.