Builder tipado para rotas de API do Next.js com validação Zod, error handling padronizado e chain de middlewares. Elimina boilerplate e garante segurança de tipos de ponta a ponta.
npm install next-api-builder zod
# ou
pnpm add next-api-builder zod// app/api/usuarios/route.ts
import { POST, created } from 'next-api-builder';
import { z } from 'next-api-builder/validation';
const criarUsuarioSchema = z.object({
nome: z.string().min(2),
email: z.string().email(),
idade: z.number().int().min(18),
});
export const POST_handler = POST()
.body(criarUsuarioSchema)
.handler(async (req, { body }) => {
// body é completamente tipado: { nome: string, email: string, idade: number }
const usuario = await db.usuarios.create({ data: body });
return created(usuario);
});// app/api/produtos/route.ts
import { GET, paginated } from 'next-api-builder';
import { z, paginationSchema } from 'next-api-builder/validation';
const querySchema = paginationSchema.extend({
categoria: z.string().optional(),
busca: z.string().optional(),
});
export const GET_handler = GET()
.query(querySchema)
.handler(async (req, { query }) => {
const { page, limit, categoria, busca } = query;
const { data, total } = await db.produtos.findMany({ page, limit, categoria, busca });
return paginated(data, page, limit, total);
});import { POST, json } from 'next-api-builder';
import type { Middleware } from 'next-api-builder';
import { UnauthorizedException } from 'next-api-builder/errors';
const authMiddleware: Middleware = async (req, next) => {
const token = req.headers.get('authorization')?.replace('Bearer ', '');
if (!token) throw new UnauthorizedException();
return next();
};
const rateLimitMiddleware: Middleware = async (req, next) => {
// sua lógica de rate limit aqui
return next();
};
export const POST_handler = POST()
.use(authMiddleware, rateLimitMiddleware)
.body(schema)
.handler(async (req, { body }) => {
return json({ ok: true });
});import {
NotFoundException,
ConflictException,
ForbiddenException,
RateLimitException,
} from 'next-api-builder/errors';
// Lançar dentro do handler — o builder captura e retorna JSON correto
throw new NotFoundException('Usuário');
// => 404: { code: "NOT_FOUND", message: "Usuário não encontrado." }
throw new ConflictException('Email já cadastrado.');
// => 409: { code: "CONFLICT", message: "Email já cadastrado." }| Função | Status | Uso |
|---|---|---|
json(data) |
200 | Resposta genérica |
created(data) |
201 | Recurso criado |
noContent() |
204 | Sem corpo |
paginated(data, page, limit, total) |
200 | Lista paginada com meta |
MIT © 2026 Tox
built by tox