Validation and Response Helpers
Validation + Consistent Responses: Making Your API Feel “Professional”
Welcome back! In this lesson, we’ll take your Task Manager API from “it works” to “it’s predictable and safe to use.” That means validating everything that comes in (so bad input can’t sneak through) and standardizing everything that goes out (so every client knows exactly what shape to expect).
You’ll do this in a very “Codex CLI” way: small, targeted prompts that touch a couple of files at a time, with clear rules about behavior and response shape. By the end, your /api/tasks, /api/tasks/[id], and /api/tasks/filter endpoints will all speak the same JSON “language,” and they’ll reject invalid requests with helpful, consistent error payloads.
Previously…
In the previous lesson, you focused on polishing the API surface: introducing response helpers and refactoring routes to use them so every response had a consistent envelope. Now we’ll build on that foundation by adding Zod-powered request validation (instead of ad-hoc checks), and we’ll apply it across create/update flows so the backend is just as strict and predictable as the response format.
How we’ll use Codex CLI in this lesson
The key habit is to treat Codex like a teammate who needs constraints. For each change, you’ll give a prompt that:
- lists the exact files Codex may modify,
- describes the exact response shape and status codes,
- and explicitly says “don’t touch anything else.”
For example:
Codex, modify only
src/lib/validation/taskSchemas.ts.Implement Zod schemas for task create/update:
createTaskSchema,putTaskSchema, andpatchTaskSchema.Keep the field rules:
title/contentrequired non-empty strings,completeddefaultfalse,dueDateoptional but must parse as a date string.Do not modify any other files. Show the full updated file.
That “only these files” pattern is what keeps vibe coding from turning into mystery refactors.
Defining task rules once with Zod schemas
Validation is easiest to maintain when you define it one time, then reuse it everywhere. In this project, that “single source of truth” for task input validation lives in src/lib/validation/taskSchemas.ts.
-
createTaskSchemadefines the exact shape your API accepts when creating tasks: requiredtitle/content, a booleancompleted(defaulting tofalse), and an optionaldueDatethat must be parseable as a date string. This keeps your API strict without needing repetitive “if/else validation” in every route. -
.refine(...)is doing the “date sanity check.” Instead of trusting that a string looks like a date, it ensuresDate.parse(...)doesn’t fail—so"not-a-date"can’t slip in and break later logic. -
putTaskSchemaandpatchTaskSchemashare the same base rules, but express different update semantics: PUT requires the full object, while PATCH makes every field optional via.partial(). This mirrors common REST expectations and keeps your update logic consistent.
