Validate queue payloads
Validate payloads before enqueueing and before running queue handlers.
Validate payloads at two boundaries:
- before you enqueue user input
- inside the queue handler before you trust the payload
Queue exports two helpers for that split: readValidatedPayload() and readValidatedJob().
Validate input before enqueueing
Use readValidatedPayload() in the route or function that accepts input.
server/api/queues/welcome.post.ts
import { createError, readBody } from 'h3'
import { readValidatedPayload, runQueue } from '@vitehub/queue'
export default defineEventHandler(async (event) => {
const { email } = await readValidatedPayload(await readBody(event), (input) => {
if (!input || typeof input !== 'object' || typeof input.email !== 'string' || !input.email.includes('@')) {
throw createError({
statusCode: 400,
statusMessage: 'Enter a valid email address.',
})
}
return {
email: input.email.trim().toLowerCase(),
}
})
return runQueue('welcome-email', { email })
})
Validate again inside the queue handler
Use readValidatedJob() in the queue definition when the handler should only work with validated data.
server/queues/welcome-email.ts
import { defineQueue, readValidatedJob } from '@vitehub/queue'
export default defineQueue(async (rawJob) => {
const job = await readValidatedJob(rawJob, (payload) => ({
email: typeof payload?.email === 'string' ? payload.email.trim().toLowerCase() : '',
}))
return {
id: job.id,
payload: job.payload,
}
})
Why validate twice
Validating before enqueueing protects the caller-facing edge.
Validating inside the handler protects the worker edge. Jobs might still come from tests, provider callbacks, replay tools, or older producers that bypass the original route.