API routes no Next.js (Route Handlers): GET, POST, autenticação | We.Inc
Exemplos de Route Handlers do Next.js para o App Router, prontos para copiar: GET com query params, POST com validação, params dinâmicos como promise, verificação de autenticação, CORS e webhooks.
No App Router, um endpoint de API é um arquivo route.ts dentro de app, por exemplo app/api/todos/route.ts. Exporte funções async com o nome dos métodos HTTP, como GET e POST; cada uma recebe um Request e retorna um Response, normalmente Response.json(). Os segmentos dinâmicos chegam como uma promise params que você aguarda com await. Desde o Next.js 15, os handlers GET são dinâmicos por padrão.
O básico dos Route Handlers
Tarefa
Código
Retornar JSON
return Response.json(data, { status: 200 })
Ler um corpo JSON
const body = await request.json()
Ler dados de formulário
const form = await request.formData()
Ler ?q=
request.nextUrl.searchParams.get("q")
Segmento dinâmico
const { id } = await params
Cookies / cabeçalhos
await cookies(), await headers() de next/headers
As API routes do Pages Router usavam os objetos req e res. Os Route Handlers usam no lugar deles os objetos padrão da Web, Request e Response, o que confunde quem copia respostas antigas. Abaixo estão os padrões de que você vai precisar em um app de verdade, todos escritos para o App Router atual, além de um pequeno testador que mostra os códigos de status que um POST com validação deve devolver.
Preencha o corpo de requisição fictício no testador e escolha se quem chama está logado.
O testador aplica no seu navegador as mesmas regras de validação do exemplo de POST desta página.
Leia o código de status e o JSON retornados e depois altere um campo para ver um 400, 401 ou 201.
Copie o handler de exemplo e troque a lista em memória pelo seu banco de dados.
Trate todo handler como um endpoint público. Verifique a sessão dentro do handler, mesmo que o proxy já tenha redirecionado os usuários não logados.
Valide o corpo com uma biblioteca de schema como o Zod e envie 400 com os erros de cada campo, em vez de deixar um payload ruim estourar um 500.
Um arquivo route.ts não pode ficar na mesma pasta que um page.tsx; coloque as APIs em app/api para mantê-los separados.
Se você não exportar OPTIONS, o Next.js responde por você com um cabeçalho Allow listando os métodos que você exportou.
Em webhooks, leia o corpo bruto com request.text() antes de fazer o parse, porque a verificação de assinatura precisa dos bytes exatos.
Perguntas frequentes
As API routes do Next.js foram descontinuadas?
As rotas pages/api continuam funcionando no Pages Router. No App Router, o equivalente é um Route Handler, um arquivo route.ts que usa os objetos Request e Response da Web e não precisa de configuração de bodyParser.
Quais métodos HTTP um route.ts pode exportar?
GET, POST, PUT, PATCH, DELETE, HEAD e OPTIONS. Chamar um método que você não exportou retorna 405 Method Not Allowed.
Por que preciso usar await em params?
Desde o Next.js 15, o params do argumento de contexto é uma promise. Escreva const { id } = await params. O tipo auxiliar RouteContext, gerado por next dev, next build ou next typegen, dá a você params tipados a partir do caminho da rota.
Os Route Handlers GET ficam em cache?
Não mais por padrão. O Next.js 15 mudou os handlers GET de estáticos para dinâmicos. Para voltar a usar cache, use export const dynamic = 'force-static' ou um valor de revalidate. Com Cache Components ativado, coloque use cache em uma função auxiliar chamada pelo handler, não no corpo do handler.
Devo usar um Route Handler ou uma Server Action?
Use uma Server Action para mutações disparadas pelos seus próprios formulários e botões. Use um Route Handler quando algo fora da sua árvore React chamar a URL: um app mobile, um webhook, um cron job ou um script de terceiros.
Estrutura de arquivos
O caminho da pasta é a URL. app/api/todos/route.ts responde em /api/todos, e app/api/todos/[id]/route.ts responde em /api/todos/42. Uma pasta catch-all como [...slug] recebe um array de segmentos.
Os Route Handlers compartilham a configuração de segmento com as páginas, então os mesmos exports dynamic, revalidate e runtime valem para eles.
Códigos de status que os clientes entendem
Envie 201 depois de criar algo, 400 quando a entrada estiver errada, 401 quando ninguém estiver logado, 403 quando o usuário logado não tiver permissão, 404 quando o registro não existir e 405 para métodos não suportados. Assim, o front-end pode decidir pelo código em vez de analisar o texto do erro.
Retorne um formato de JSON consistente para os erros, como { error: string, fields?: object }, para que um único helper de fetch consiga tratar todos eles.
Checklist de segurança
Verifique a sessão, confira se o usuário é dono do registro que está alterando, valide o payload e nunca devolva segredos ou linhas completas de usuário. O guia oficial de autenticação mostra esse padrão em duas etapas: 401 quando não há sessão e 403 quando o papel é o errado.
Defina cabeçalhos CORS apenas nos handlers que outras origens realmente precisam chamar, e liste as origens específicas em vez de um asterisco sempre que houver cookies envolvidos.
Exemplos de Route Handlers
GET com uma busca na query
app/api/todos/route.ts. O parâmetro q filtra a lista; uma busca vazia retorna tudo.
POST com validação Zod e verificação de autenticação
Retorna 401 sem sessão, 400 com erros por campo para um corpo inválido e, caso contrário, 201 com o novo registro. getSession representa a sua biblioteca de autenticação.
Segmento dinâmico com params aguardados
app/api/todos/[id]/route.ts. params é uma promise no Next.js 15 e versões posteriores.
CORS para uma origem confiável
Responde ao preflight do navegador e à requisição real com a mesma origem permitida.
Chamando o handler a partir de um Client Component
O helper de fetch lê primeiro o código de status, para que o formulário possa mostrar os erros por campo de um 400.
API routes do Pages Router vs Route Handlers
A mesma tarefa, APIs diferentes
pages/api/x.ts
app/api/x/route.ts
Handler
export default function handler(req, res)
export async function GET(request)
Enviar JSON
res.status(200).json(data)
return Response.json(data)
Escolha do método
if (req.method === "POST")
uma função POST exportada separadamente
Parse do corpo
req.body (configuração bodyParser)
await request.json() ou request.formData()
Query string
request.nextUrl.searchParams
Testador de POST
Edite um corpo JSON, escolha se quem chama está logado e veja o código de status e a resposta que o exemplo de POST com validação devolveria.
Método
Corpo da requisição (JSON)
Quem chama tem uma sessão válida
Resposta
PUT mostra o 405 que o Next.js envia para um método que o arquivo não exporta.