Building Type-Safe APIs with Nuxt 3 and Prisma
Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.
A comprehensive security checklist covering authentication, input validation, rate limiting, and common vulnerabilities in Node.js APIs.
Mbeah Essilfie
July 7, 2026 at 06:03 AM
Every API deployed to production is a target. This isn't about paranoia — it's about building habits that prevent breaches.
Never trust user input. Validate everything at the boundary:
import { z } from 'zod'
const UserInputSchema = z.object({
email: z.string().email().max(254),
name: z.string().min(1).max(100).trim(),
age: z.number().int().min(13).max(150),
})
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const validated = UserInputSchema.parse(body) // Throws on invalid input
// Use validated data — it's safe
})
// Middleware: verify JWT on protected routes
export default defineEventHandler(async (event) => {
const token = getHeader(event, 'Authorization')?.replace('Bearer ', '')
if (!token) throw createError({ statusCode: 401, message: 'Unauthorized' })
try {
const payload = verifyJWT(token)
event.context.user = payload
} catch {
throw createError({ statusCode: 401, message: 'Invalid token' })
}
})
// Simple in-memory rate limiter (use Redis for production clusters)
const requests = new Map<string, { count: number; resetAt: number }>()
function rateLimit(ip: string, limit = 100, windowMs = 60000): boolean {
const now = Date.now()
const record = requests.get(ip)
if (!record || now > record.resetAt) {
requests.set(ip, { count: 1, resetAt: now + windowMs })
return true
}
if (record.count >= limit) return false
record.count++
return true
}
Always use parameterized queries (Prisma does this by default):
// ❌ NEVER do this
const user = await prisma.$queryRawUnsafe(`SELECT * FROM users WHERE id = '${userId}'`)
// ✅ Always use parameterized queries
const user = await prisma.user.findUnique({ where: { id: userId } })
// server/middleware/security-headers.ts
export default defineEventHandler((event) => {
setHeaders(event, {
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'Content-Security-Policy': "default-src 'self'",
})
})
pnpm audit)Fullstack Software Developer
Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.
Go beyond basic utility classes and learn how to build cohesive, maintainable design systems with Tailwind CSS.
Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.
