Back to list
teocrafters

zod-schema-creation

by teocrafters

0🍴 0📅 Jan 25, 2026

SKILL.md


name: zod-schema-creation description: Guide through creating Zod validation schemas with i18n integration for API request validation. Use when creating API endpoints that need validation.

Zod Validation Schema Creation Skill

Guides through creating Zod validation schemas with i18n integration for API request validation.

Purpose

USE this skill when:

  • Creating new API endpoints that accept request bodies
  • Adding validation for POST, PUT, or PATCH requests
  • Implementing form validation schemas

Critical Rules

⚠️ Factory pattern REQUIRED - Schemas must accept translation function t: (key: string) => string ⚠️ i18n keys in errors - All error messages use translation keys, not hardcoded text ⚠️ File organization - All schemas in shared/utils/schemas/ directory ⚠️ Type export - Always export TypeScript type using z.infer<ReturnType<...>>

Workflow Steps

Step 1: Identify Validation Requirements

  • What fields are required/optional?
  • What validation rules apply?
  • Creating (create schema) or updating (update schema)?

Step 2: Create Schema File

Location: shared/utils/schemas/{resource}.ts

Step 3: Implement Factory Function Pattern

import { z } from "zod"

export function createSpeakerSchema(t: (key: string) => string) {
  return z.object({
    firstName: z
      .string()
      .min(1, t("validation.firstNameRequired"))
      .max(100, t("validation.firstNameTooLong")),
    
    lastName: z
      .string()
      .min(1, t("validation.lastNameRequired"))
      .max(100),
    
    email: z
      .string()
      .email(t("validation.emailInvalid"))
      .optional(),
  })
}

Step 4: Export TypeScript Type

export type CreateSpeakerInput = z.infer<ReturnType<typeof createSpeakerSchema>>

Step 5: Create Update Schema (If Needed)

export function updateSpeakerSchema(t: (key: string) => string) {
  return createSpeakerSchema(t).partial()
}

export type UpdateSpeakerInput = z.infer<ReturnType<typeof updateSpeakerSchema>>

Step 6: Update Barrel File

Add to shared/utils/schemas/index.ts:

export * from "./speaker"

Step 7: Add Translation Keys

Use i18n-key-validation skill to ensure keys exist in both pl.json and en.json

Step 8: Implement in API Route

import { createSpeakerSchema } from "#shared/utils/schemas"

export default defineEventHandler(async (event) => {
  const body = await validateBody(event, createSpeakerSchema)
  
  // body is now typed and validated
  const db = useDrizzle()
  const [speaker] = await db.insert(tables.speakers)
    .values({
      id: crypto.randomUUID(),
      ...body,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .returning()
  
  return speaker
})

Common Validation Patterns

// String with length
field: z.string().min(1, t("validation.required")).max(200)

// Email
email: z.string().email(t("validation.emailInvalid")).optional()

// Number
age: z.number().min(0).max(150)

// Enum
status: z.enum(["active", "archived"])

// Array
tags: z.array(z.string()).max(10)

Anti-Patterns

❌ Hardcoded error messages ❌ No factory pattern ❌ Wrong file location ❌ Missing type export

References

  • Backend guidelines: server/AGENTS.md
  • i18n patterns: .agents/i18n-patterns.md

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon