Validate all external input with Zod before Prisma operations. Use when accepting user input, API requests, or form data.
Validates all external input with Zod before Prisma operations. Use when accepting user input, API requests, or form data to ensure type safety and prevent database errors.
/plugin marketplace add djankies/claude-configs/plugin install prisma-6@claude-configsThis skill is limited to using the following tools:
Always validate external input with Zod before Prisma operations. Never trust user-provided data, API requests, or form submissions. Use type-safe validation pipelines that match Prisma schema types.
External Input → Zod Validation → Transform → Prisma Operation
import { z } from 'zod'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
age: z.number().int().positive().optional()
})
async function createUser(rawInput: unknown) {
const validatedData = createUserSchema.parse(rawInput)
return await prisma.user.create({
data: validatedData
})
}
model User {
id String @id @default(cuid())
email String @unique
name String
phone String?
website String?
age Int?
createdAt DateTime @default(now())
}
import { z } from 'zod'
const phoneRegex = /^\+?[1-9]\d{1,14}$/
const userCreateSchema = z.object({
email: z.string().email().toLowerCase(),
name: z.string().min(1).max(100).trim(),
phone: z.string().regex(phoneRegex).optional(),
website: z.string().url().optional(),
age: z.number().int().min(0).max(150).optional()
})
const userUpdateSchema = userCreateSchema.partial()
type UserCreateInput = z.infer<typeof userCreateSchema>
type UserUpdateInput = z.infer<typeof userUpdateSchema>
const emailSchema = z.string().email().toLowerCase().trim()
const urlSchema = z.string().url().refine(
(url) => url.startsWith('https://'),
{ message: 'URL must use HTTPS' }
)
const phoneSchema = z.string().regex(
/^\+?[1-9]\d{1,14}$/,
'Invalid phone number format'
)
const slugSchema = z.string()
.min(1)
.max(100)
.regex(/^[a-z0-9-]+$/, 'Slug must contain only lowercase letters, numbers, and hyphens')
const dateSchema = z.coerce.date().refine(
(date) => date > new Date(),
{ message: 'Date must be in the future' }
)
import { z } from 'zod'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const createPostSchema = z.object({
title: z.string().min(1).max(200),
content: z.string().min(1),
authorId: z.string().cuid(),
published: z.boolean().default(false),
tags: z.array(z.string()).max(10).optional()
})
export async function POST(request: Request) {
try {
const rawBody = await request.json()
const validatedData = createPostSchema.parse(rawBody)
const post = await prisma.post.create({
data: validatedData
})
return Response.json(post)
} catch (error) {
if (error instanceof z.ZodError) {
return Response.json(
{ errors: error.errors },
{ status: 400 }
)
}
throw error
}
}
import { z } from 'zod'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const profileUpdateSchema = z.object({
name: z.string().min(1).max(100).trim(),
bio: z.string().max(500).trim().optional(),
website: z.string().url().optional().or(z.literal('')),
location: z.string().max(100).trim().optional(),
birthDate: z.coerce.date().max(new Date()).optional()
})
async function updateProfile(userId: string, formData: FormData) {
const rawData = {
name: formData.get('name'),
bio: formData.get('bio'),
website: formData.get('website'),
location: formData.get('location'),
birthDate: formData.get('birthDate')
}
const validatedData = profileUpdateSchema.parse(rawData)
return await prisma.user.update({
where: { id: userId },
data: validatedData
})
}
import { z } from 'zod'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const addressSchema = z.object({
street: z.string().min(1).max(200),
city: z.string().min(1).max(100),
state: z.string().length(2).toUpperCase(),
zipCode: z.string().regex(/^\d{5}(-\d{4})?$/)
})
const createCompanySchema = z.object({
name: z.string().min(1).max(200),
email: z.string().email().toLowerCase(),
website: z.string().url().optional(),
address: addressSchema
})
async function createCompany(rawInput: unknown) {
const validatedData = createCompanySchema.parse(rawInput)
return await prisma.company.create({
data: {
name: validatedData.name,
email: validatedData.email,
website: validatedData.website,
address: {
create: validatedData.address
}
},
include: {
address: true
}
})
}
import { z } from 'zod'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const bulkUserSchema = z.object({
users: z.array(
z.object({
email: z.string().email().toLowerCase(),
name: z.string().min(1).max(100),
role: z.enum(['USER', 'ADMIN'])
})
).min(1).max(100)
})
async function createBulkUsers(rawInput: unknown) {
const validatedData = bulkUserSchema.parse(rawInput)
const uniqueEmails = new Set(validatedData.users.map(u => u.email))
if (uniqueEmails.size !== validatedData.users.length) {
throw new Error('Duplicate emails in bulk operation')
}
return await prisma.$transaction(
validatedData.users.map(user =>
prisma.user.create({ data: user })
)
)
}
import { z } from 'zod'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const passwordSchema = z.string()
.min(8)
.refine((pwd) => /[A-Z]/.test(pwd), {
message: 'Password must contain uppercase letter'
})
.refine((pwd) => /[a-z]/.test(pwd), {
message: 'Password must contain lowercase letter'
})
.refine((pwd) => /[0-9]/.test(pwd), {
message: 'Password must contain number'
})
const registerSchema = z.object({
email: z.string().email().toLowerCase(),
password: passwordSchema,
confirmPassword: z.string()
}).refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ['confirmPassword']
})
import { z } from 'zod'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const createUserSchema = z.object({
email: z.string().email().toLowerCase(),
username: z.string().min(3).max(30).regex(/^[a-z0-9_]+$/)
})
async function createUserWithChecks(rawInput: unknown) {
const validatedData = createUserSchema.parse(rawInput)
const existing = await prisma.user.findFirst({
where: {
OR: [
{ email: validatedData.email },
{ username: validatedData.username }
]
}
})
if (existing) {
if (existing.email === validatedData.email) {
throw new Error('Email already exists')
}
if (existing.username === validatedData.username) {
throw new Error('Username already taken')
}
}
return await prisma.user.create({
data: validatedData
})
}
import { z } from 'zod'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const updateSettingsSchema = z.object({
theme: z.enum(['light', 'dark']).default('light'),
notifications: z.boolean().default(true),
language: z.string().length(2).default('en')
})
async function updateSettings(userId: string, rawInput: unknown) {
const result = updateSettingsSchema.safeParse(rawInput)
if (!result.success) {
return {
success: false,
errors: result.error.errors
}
}
const settings = await prisma.userSettings.upsert({
where: { userId },
update: result.data,
create: {
userId,
...result.data
}
})
return {
success: true,
data: settings
}
}
async function createUser(data: any) {
return await prisma.user.create({ data })
}
async function createUserFromAdmin(data: unknown) {
return await prisma.user.create({ data })
}
async function createUser(data: unknown) {
const user = await prisma.user.create({ data })
const validated = schema.parse(user)
return validated
}
import { z } from 'zod'
import { Prisma } from '@prisma/client'
const userCreateSchema = z.object({
email: z.string().email(),
name: z.string()
}) satisfies z.Schema<Prisma.UserCreateInput>
type ValidatedUserInput = z.infer<typeof userCreateSchema>
Zod v4 Validation:
TypeScript Validation:
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.