API en Next.js · Paso 9 de 9
Tu primer CRUD: productos por API
Listar y crear productos desde route.ts con validación mínima del cuerpo JSON.
El CRUD son las cuatro operaciones habituales: crear, leer, actualizar y borrar. Para no mezclar todo a la vez, aquí solo lees la lista y creas un producto: suficiente para ver el recorrido completo petición → Prisma → respuesta JSON.
Coloca el archivo en app/api/productos/route.ts. La URL pública será /api/productos.
GET — listar productos
import { NextResponse } from "next/server"
import { prisma } from "@/lib/prisma"
export async function GET() {
const productos = await prisma.producto.findMany({
orderBy: { id: "asc" },
})
return NextResponse.json(productos)
}
findMany devuelve un array; vacío al principio, hasta que insertes datos.
POST — crear un producto
El cuerpo llega como JSON. Comprueba el método y parsea con cuidado:
import { NextResponse } from "next/server"
import { prisma } from "@/lib/prisma"
export async function POST(request: Request) {
let body: unknown
try {
body = await request.json()
} catch {
return NextResponse.json({ error: "JSON inválido" }, { status: 400 })
}
if (!body || typeof body !== "object") {
return NextResponse.json({ error: "Cuerpo vacío" }, { status: 400 })
}
const { nombre, precio, stock } = body as {
nombre?: unknown
precio?: unknown
stock?: unknown
}
if (typeof nombre !== "string" || nombre.trim() === "") {
return NextResponse.json({ error: "nombre es obligatorio" }, { status: 400 })
}
if (typeof precio !== "number" || Number.isNaN(precio)) {
return NextResponse.json({ error: "precio debe ser un número" }, { status: 400 })
}
const stockNum =
typeof stock === "number" && !Number.isNaN(stock) ? Math.trunc(stock) : 0
const creado = await prisma.producto.create({
data: {
nombre: nombre.trim(),
precio,
stock: stockNum,
},
})
return NextResponse.json(creado, { status: 201 })
}
Los nombres producto, create, findMany coinciden con el modelo Producto en Prisma (primera letra minúscula en el cliente).
Probar en local
Con npm run dev:
- Navegador o GET:
http://localhost:3000/api/productos→ lista (puede ser[]). - POST con
curl(ejemplo):
curl -X POST http://localhost:3000/api/productos \
-H "Content-Type: application/json" \
-d '{"nombre":"Agua","precio":1.2,"stock":24}'
Deberías recibir el objeto creado con id asignado. Repite el GET y verás el nuevo registro.
Siguiente paso natural
Cuando domines crear y listar, podrás añadir GET por id, PATCH para actualizar precio o stock y DELETE con prisma.producto.delete. El mismo patrón: función exportada por método HTTP en route.ts, validación del cuerpo y respuestas con códigos adecuados (404 si no existe el registro).
Cuando hayas leído el texto, marca la lección para seguir el progreso.