Skip to content

feat(api): zod validation #4

@perzeuss

Description

@perzeuss

✅ Add Zod Validation to API Endpoints

📋 Overview

Currently, input validation for the todos API endpoints is handled manually using custom logic. This ticket is to replace that custom validation with robust schemas using the Zod library for all relevant request payloads. Validating inputs declaratively ensures the API is easier to maintain, more extensible, and provides consistent error messages.


🎯 Acceptance Criteria

  • All applicable API endpoints under app/api/todos/ use Zod schemas for validating request bodies
    • Creating a todo (POST /api/todos)
    • Updating a todo (PUT /api/todos/[id])
  • Endpoints return descriptive 400 errors with validation details on invalid input
  • Remove now-redundant custom validation checks (e.g., if (!body.text || typeof body.text !== "string" || !body.text.trim()) ...)
  • Error structure aligns with Zod’s formatted error output
  • Code is clean, concise, and has no duplicated validation logic

🔧 Technical Requirements

  • Install Zod (npm install zod)
  • Define and export a todoSchema, and any other necessary Zod schemas, in a single shared file, e.g., lib/validation/todo.ts
  • Use the Zod schema’s .safeParse() method (or .parse()/.refine() as appropriate) within the API route handlers
  • Refactor out all manual validation logic, calling Zod instead
  • Error responses return:
    • status: 400
    • A JSON body with error details from Zod

🚫 Out of Scope

  • Response validation (focus only on request validation)
  • Adding new API endpoints beyond the todos already present
  • Authentication checks
  • Custom error messages (using plain zod validation error messages is allowed)

✅ Getting Started

1. Install Zod

npm install zod

2. Define the schema(s)

For example, in lib/validation/todo.ts:

import { z } from "zod"

export const createTodoSchema = z.object({
  text: z.string().min(1, "Todo text is required").max(255)
})

3. Use in API handler (example):

import { createTodoSchema } from "@/lib/validation/todo"

export async function POST(request: NextRequest) {
  const body = await request.json()
  const validation = createTodoSchema.safeParse(body)
  if (!validation.success) {
    return NextResponse.json({ error: validation.error.format() }, { status: 400 })
  }
  // continue with validated data: validation.data
}

4. Remove previous custom validation logic.


📚 Resources


💡 Tips

  • Define all validation schemas in one place and re-use them
  • Customize error messages in the Zod schemas for clarity
  • Use .trim() in the Zod string schemas as needed

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions