Capítulo 347 de 456

API Routes

Core Idea

Qualquer arquivo em pages/api vira um endpoint server-side (/api/*) no Pages Router, sem aumentar o bundle client-side. Equivalente ao Route Handler do App Router.

Key Concepts

  • pages/api/*.ts: handler (req, res) => {} mapeado para /api/*; roda só no servidor.
  • NextApiRequest / NextApiResponse: tipos TypeScript para request/response, com helpers estilo Express.
  • req.cookies / req.query / req.body: request helpers built-in, com parsing automático por content-type.
  • config.api.bodyParser: desliga (false) ou limita (sizeLimit) o parsing automático do body (ex. para validar webhooks assinados).
  • config.api.externalResolver: sinaliza que a rota é tratada por um resolver externo (express/connect), suprime warnings.
  • config.api.responseLimit: limite de aviso do tamanho de resposta (default 4MB); pode virar false ou número/string de bytes.
  • config.maxDuration: duração máxima (segundos) permitida para a function executar.
  • Dynamic/catch-all API routes: [pid].ts, [...slug].ts, [[...slug]].ts seguem as mesmas regras de pages/.
  • Response helpers: res.status(), res.json(), res.send(), res.redirect(), res.revalidate(urlPath).

Code Examples

import type { NextApiRequest, NextApiResponse } from 'next'

type ResponseData = { message: string }

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}
  • O que demonstra: handler básico tipado com resposta JSON.
export const config = {
  api: {
    bodyParser: false,
  },
}
  • O que demonstra: desabilita o parsing automático do body, necessário para validar payloads brutos de webhook (ex. GitHub).
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { slug } = req.query
  res.end(`Post: ${slug.join(', ')}`)
}
  • O que demonstra: catch-all route recebe slug sempre como array na query.

Reference Tables

ConfigDefaultUso
bodyParsertruefalse para consumir body como Stream/raw-body
bodyParser.sizeLimit'1mb'limite do body parseado
externalResolverfalsetrue quando express/connect resolve a rota
responseLimit'4mb' (aviso)false desliga o aviso; aceita bytes ou string ('8mb')
maxDuration-segundos máximos de execução
Padrão de rotaExemplo de match
pages/api/post/create.js/api/post/create (precedência máxima)
pages/api/post/[pid].js/api/post/1, /api/post/abc
pages/api/post/[...slug].js/api/post/a/b/c
pages/api/post/[[...slug]].js/api/post, /api/post/a, ... (opcional)

Anti-patterns

  • Depender de CORS automático: API Routes são same-origin only por padrão; headers CORS precisam ser adicionados manualmente.
  • Usar API Routes com static export: não funciona; Route Handlers do App Router suportam static export, API Routes não.
  • Confundir precedência de rotas: rotas predefinidas > dinâmicas > catch-all; uma rota específica sempre vence a genérica.

Key Takeaways

  1. pages/api é server-only: nunca infla o bundle do cliente.
  2. bodyParser: false é o caminho para verificar assinaturas de webhook no raw body.
  3. Catch-all ([...slug]) sempre entrega array; optional catch-all ([[...slug]]) também casa a rota sem parâmetro.
  4. Streaming é suportado via res.writeHead/res.write, mas a doc recomenda Route Handlers do App Router no Next.js 14+.

Connects To

  • custom-app / getStaticProps: API Routes não participam do data fetching de páginas, mas podem ser chamadas por elas ou substituídas por lógica compartilhada em lib/.