name: noony-validation-schemas description: Use when validating request bodies with Zod schemas, understanding parsedBody vs validatedBody, ordering BodyParserMiddleware before BodyValidationMiddleware, handling Pub/Sub message validation, defining async validation, or inferring TypeScript types from Zod schemas in Noony handlers.
skill:noony-validation-schemas
Does exactly this
Provides Zod integration patterns for Noony: schema definition with z.infer, the parsedBody-to-validatedBody pipeline, middleware ordering per noony-middleware-ordering, Pub/Sub message validation, and async validation with database lookups.
When to use
- "Validate request body"
- "Use Zod schema"
- "parsedBody vs validatedBody"
- "Pub/Sub message validation"
- "Async validation with database lookup"
- "How to test validation"
Do not use this skill when
- You need error class selection ->
noony-error-handlingfor error types and cause chaining - You need middleware ordering beyond validation ->
noony-middleware-orderingis the canonical reference - You need custom middleware development ->
noony-middleware-development - You need path parameter validation ->
noony-path-parametershandles route params - You need type inference guidance ->
noony-type-inferencefor generics flow
Steps
- Define Zod schema and infer TypeScript type via
z.infer<typeof schema>— never define a separate interface -> Seereferences/validation-patterns.md#basic-object-schemafor code - Verify middleware ordering per
noony-middleware-ordering: ErrorHandlerMiddleware (position 1) -> BodyParserMiddleware (position 6) -> BodyValidationMiddleware (position 7) — parser converts raw body toparsedBody, validator checksparsedBodyagainst schema and populatesvalidatedBody-> Seereferences/validation-patterns.md#middleware-orderfor the pipeline - Pass the inferred type to Handler:
new Handler<CreateUserRequest, AuthUser>()— usingunknownmakesvalidatedBodyuntyped - In handler, access validated data via
context.req.validatedBody!(notbodyorparsedBody) - For Pub/Sub messages, validate the envelope first (base64 decode via transform), then validate the decoded content with a second schema
-> See
references/validation-patterns.md#pubsub-message-validation - For async validation (database lookups), add
{ async: true }option toBodyValidationMiddleware-> Seereferences/validation-patterns.md#async-validation
Rules
- Never access
context.req.bodydirectly — always usevalidatedBodyafter validation middleware - Always use
z.infer<typeof schema>for TypeScript types — single source of truth, no interface drift BodyParserMiddlewareMUST come beforeBodyValidationMiddleware— positions 6 and 7 in the canonical order (seenoony-middleware-ordering)ErrorHandlerMiddlewareMUST be present at position 1 (seenoony-middleware-ordering) — without it,ValidationErrorcrashes the function instead of returning a clean 400- Async validation requires
{ async: true }option — without it, async refinements silently break - Define schemas at module scope, not inside handlers — schema compilation happens once
- Place expensive
.refine()checks last — cheap format checks fail first for better performance
Anti-patterns
- Accessing
context.req.bodydirectly — unsafe, untyped, bypasses the validation pipeline - Skipping
BodyParserMiddleware—parsedBodywill be undefined, validation has nothing to work with - Forgetting
BodyParserMiddlewarebeforeBodyValidationMiddleware— positions 6 then 7 pernoony-middleware-ordering; reversing them breaks the pipeline - Defining TypeScript interface separately from Zod schema — duplicates type definition, can drift out of sync
- Validating inside the handler (
schema.safeParse(body)) — defeats middleware pipeline benefits, duplicates error handling - Using
context.req.parsedBodyafterBodyValidationMiddleware— usevalidatedBodywhich is type-safe Handler<unknown>with validation —validatedBodystays typed asunknowneven after validation- Missing
ErrorHandlerMiddleware—ValidationErrorcrashes the function instead of returning structured 400 JSON
Done when
- You can define Zod schemas and infer types with
z.infer - You understand the parsedBody -> validatedBody pipeline
- You know middleware ordering per
noony-middleware-ordering: ErrorHandler (1) -> BodyParser (6) -> BodyValidation (7) - You can validate Pub/Sub messages (envelope + decoded content)
- You know when and how to use async validation
If you need more detail
-> references/validation-patterns.md — Middleware pipeline, schema patterns (basic, nested, arrays, enums, custom refinements), Pub/Sub validation, async validation, error response format, testing examples