Validate payloads
Validate request payloads before passing them to a sandbox definition.
Validate user input before it crosses the sandbox boundary. The route should pass a shaped payload to runSandbox(), not whatever the client sent.
Validate after reading the body
import { readRequestPayload, readValidatedPayload } from '@vitehub/sandbox'
const body = await readRequestPayload(event, { notes: '' })
const payload = await readValidatedPayload(body, (value) => {
if (!value || typeof value !== 'object') return false
return {
notes: String((value as { notes?: unknown }).notes || ''),
}
})
Then call the sandbox:
const result = await runSandbox('release-notes', payload)
Use a function validator
A function validator can:
- return
trueto keep the original value - return
falseto fail validation - return a transformed value
- throw an error to fail validation
const payload = await readValidatedPayload(body, (value) => {
if (!value || typeof value !== 'object') return false
const notes = String((value as { notes?: unknown }).notes || '').trim()
if (!notes) return false
return { notes }
})
Customize validation errors
Use onError when you need a route-specific error shape:
const payload = await readValidatedPayload(body, validateReleaseNotes, {
onError() {
return createError({
statusCode: 400,
statusMessage: 'Expected a non-empty notes field.',
})
},
})
Full route
server/api/release-notes.post.ts
import { readRequestPayload, readValidatedPayload, runSandbox } from '@vitehub/sandbox'
export default defineEventHandler(async (event) => {
const body = await readRequestPayload(event, { notes: '' })
const payload = await readValidatedPayload(body, (value) => {
if (!value || typeof value !== 'object') return false
return { notes: String((value as { notes?: unknown }).notes || '') }
})
const result = await runSandbox('release-notes', payload)
if (result.isErr()) {
throw createError({ statusCode: 500, statusMessage: result.error.message })
}
return { result: result.value }
})

