Runtime validation with a plain function
Use case
Validate API responses using a simple function without any schema library.
Smallest working example
import { createClient } from '@parcely/core'
const http = createClient({ baseURL: 'https://api.example.com' })
interface User {
id: string
name: string
}
function validateUser(input: unknown): User {
if (
typeof input === 'object' && input !== null &&
'id' in input && typeof (input as User).id === 'string' &&
'name' in input && typeof (input as User).name === 'string'
) {
return input as User
}
throw new Error('Invalid user data')
}
const { data } = await http.get('/users/me', {
validate: validateUser,
})
// data is typed as User
How it works
parcely's Validator<T> type accepts (input: unknown) => T functions. The function receives the parsed response body. If it returns a value, that value becomes data. If it throws, parcely wraps the error in HttpError with code: 'ERR_VALIDATION'.
Error handling
import { isHttpError } from '@parcely/core'
try {
await http.get('/users/me', { validate: validateUser })
} catch (err) {
if (isHttpError(err) && err.code === 'ERR_VALIDATION') {
console.log('Validation failed:', err.cause)
}
}
Axios equivalent
Axios does not support validation. You would validate after the response:
// axios:
const { data } = await http.get('/users/me')
const user = validateUser(data) // manual
// parcely (integrated):
const { data: user } = await http.get('/users/me', { validate: validateUser })
Notes and gotchas
- The function validator is the simplest option -- no library needed.
- Resolution order for the
Validator<T>type: Standard Schema v1 (detected via~standardproperty), then.parse()method, then function call. - The validator runs after response parsing and before the response envelope is returned.