API Routes no Next.js: como criar endpoints profissionais

API Routes no Next.js: como criar endpoints profissionais - hero

API Routes no Next.js: como criar endpoints profissionais

Índice

Se você já tentou enviar um formulário de contato em um site estático e bateu de frente com a complexidade de configurar um servidor separado, este conteúdo é para você. As API Routes do Next.js resolvem exatamente esse tipo de dor: permitem criar pequenos serviços de backend dentro do próprio projeto Next.js, sem precisar subir uma aplicação Node.js adicional nem configurar rotas em um servidor Express. É a famosa ideia de tudo em um lugar só, com a vantagem de manter o código organizado e fácil de manter.

A boa notícia é que, mesmo sem experiência prévia em backend, dá para criar uma API funcional em poucos minutos. Ao longo deste guia, você vai entender o que são as API Routes, como elas funcionam na versão atual do Next.js (App Router), como validar dados, tratar erros, proteger endpoints e até substituir parte delas por uma abordagem mais moderna chamada Server Actions. O tom é direto, com exemplos reais e explicações pensadas para quem está começando agora.

O que são API Routes no Next.js

O que são API Routes no Next.js - imagem ilustrativa
O que são API Routes no Next.js

API Routes são endpoints de backend que rodam dentro do seu projeto Next.js, ou seja, no mesmo servidor que entrega as páginas do site. Cada rota responde a uma URL específica e pode receber requisições HTTP como GET, POST, PUT, PATCH e DELETE, retornando dados em formato JSON para o front-end consumir.

Na prática, pense nelas como microfunções que ficam escutando requisições em determinados endereços. Quando alguém (um formulário no site, um aplicativo mobile, um sistema externo) acessa essa URL com o método correto, a sua função é executada no servidor e devolve uma resposta. Não há mistério: é o mesmo conceito de endpoint que existe em qualquer API REST.

A grande vantagem é a integração nativa com o restante do projeto. Você compartilha tipos do TypeScript, acessa variáveis de ambiente com o mesmo processo, usa o mesmo deploy e ainda aproveita otimizações automáticas do Next.js, como edge runtime e caching.

Evolução: Pages Router vs App Router

Antes de 2023, as API Routes eram criadas dentro da pasta pages/api, e cada arquivo representava uma rota. Com a chegada do App Router (estável a partir do Next.js 13.4 e consolidado em 2024 e 2025), as rotas passaram a ser definidas dentro da pasta app/api usando arquivos especiais chamados Route Handlers.

Hoje, em 2026, a recomendação oficial da Vercel e da documentação do Next.js é usar o App Router como padrão. O Pages Router continua funcionando e recebendo correções de segurança, mas não recebe mais novos recursos. Por isso, todos os exemplos deste artigo usam a abordagem moderna com app/api.

A tabela abaixo resume as principais diferenças:

Característica Pages Router (pages/api) App Router (app/api)
Pasta padrão pages/api app/api
Arquivo por rota Qualquer arquivo .js ou .ts route.ts ou route.js
Métodos HTTP Funções nomeadas (GET, POST) Funções nomeadas exportadas
Status Legado, ainda suportado Padrão atual recomendado
Integração com React Server Components Limitada Total
Suporte a streaming Não Sim
Novos recursos Não recebe mais Recebe atualizações

Quando usar API Routes (e quando não usar)

API Routes brilham em cenários como:

  • Receber dados de formulários de contato ou cadastro.
  • Criar pequenos webhooks para integração com terceiros.
  • Servir dados para um front-end em Next.js ou outro framework.
  • Proteger chaves de API que não podem ficar expostas no navegador.
  • Atender requisições vindas de aplicativos mobile.

Por outro lado, elas não são a melhor escolha quando:, Você precisa de um backend complexo com autenticação avançada, filas, agendamento de tarefas ou microserviços. Nesse caso, um backend dedicado (Node.js com NestJS, Python com Django, Go, entre outros) é mais adequado, Você só precisa transformar dados no front-end. Aí pode usar Server Actions, que é uma forma mais simples de chamar lógica de servidor sem criar uma rota HTTP tradicional

Como criar sua primeira API Route

Como criar sua primeira API Route - imagem ilustrativa
Como criar sua primeira API Route

Vamos colocar a mão na massa. O exemplo a seguir mostra como criar uma rota simples que retorna a data e hora atuais em formato JSON. É o famoso "Hello World" das APIs, ideal para confirmar que tudo está funcionando.

Estrutura de pastas no App Router

Para criar uma rota, basta adicionar um arquivo chamado route.ts (ou route.js, se não usar TypeScript) dentro de uma pasta em app/api. O nome da pasta vira o caminho da URL.

Por exemplo, a pasta app/api/hora/route.ts cria o endpoint /api/hora. Não confunda com page.tsx, que cria páginas. Cada pasta dentro de app deve ter apenas um dos dois: ou renderiza uma página (com page.tsx) ou expõe uma API (com route.ts).

Exemplo básico com método GET

O código abaixo cria uma rota que responde a requisições GET e devolve a hora atual em JSON.

// app/api/hora/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  const agora = new Date().toISOString();
  return NextResponse.json({
    sucesso: true,
    horario: agora,
    mensagem: 'Requisição processada com sucesso'
  });
}

Para testar, basta rodar npm run dev (ou pnpm dev ou yarn dev, dependendo do seu gerenciador de pacotes) e acessar http://localhost:3000/api/hora no navegador. Você verá a resposta em JSON.

Note que exportamos uma função chamada GET. O Next.js reconhece automaticamente o nome da função como o método HTTP. Você pode exportar quantos métodos quiser no mesmo arquivo: GET, POST, PUT, PATCH, DELETE. Cada um vira um handler independente.

Adicionando um método POST

Para receber dados enviados pelo cliente, usamos o método POST. O segundo parâmetro da função traz o objeto Request, que contém o corpo, os cabeçalhos e outras informações da requisição.

// app/api/contato/route.ts
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  try {
    const dados = await request.json();
    const { nome, email, mensagem } = dados;

    if (!nome || !email || !mensagem) {
      return NextResponse.json(
        { erro: 'Todos os campos são obrigatórios' },
        { status: 400 }
      );
    }

    // Aqui você salvaria no banco, enviaria e-mail, etc.
    console.log('Contato recebido:', { nome, email, mensagem });

    return NextResponse.json(
      { sucesso: true, mensagem: 'Mensagem recebida com sucesso' },
      { status: 201 }
    );
  } catch (erro) {
    return NextResponse.json(
      { erro: 'JSON inválido ou erro interno' },
      { status: 500 }
    );
  }
}

Esse endpoint recebe um JSON com nome, email e mensagem, valida os campos e devolve uma resposta apropriada. Para testar de verdade, use ferramentas como Postman, Insomnia ou o próprio curl no terminal.

Parâmetros dinâmicos e parâmetros de busca

Parâmetros dinâmicos e parâmetros de busca - imagem ilustrativa
Parâmetros dinâmicos e parâmetros de busca

API Routes suportam dois tipos principais de parâmetros: os dinâmicos (definidos na URL) e os de busca (enviados como query string).

Parâmetros dinâmicos na URL

Para criar uma rota que receba um identificador na URL, basta usar colchetes no nome da pasta. Por exemplo, app/api/usuarios/[id]/route.ts cria o endpoint /api/usuarios/123, onde id é o valor dinâmico.

// app/api/usuarios/[id]/route.ts
import { NextResponse } from 'next/server';

export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const id = params.id;

  // Aqui você buscaria o usuário no banco pelo id
  return NextResponse.json({
    sucesso: true,
    usuario: {
      id,
      nome: 'Exemplo de usuário',
      criadoEm: new Date().toISOString()
    }
  });
}

Também dá para usar parâmetros catch-all com [...slug], que captura vários segmentos da URL, ou parâmetros opcionais com [[...slug]].

Parâmetros de busca (query string)

Quando o cliente envia parâmetros depois do ponto de interrogação na URL (como /api/produtos?categoria=eletronicos&limite=10), você acessa esses valores com URL e URLSearchParams.

// app/api/produtos/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const categoria = searchParams.get('categoria');
  const limite = Number(searchParams.get('limite')) || 20;

  // Aqui você filtraria os produtos pela categoria
  return NextResponse.json({
    sucesso: true,
    filtros: { categoria, limite },
    produtos: []
  });
}

Esse padrão é comum para listas paginadas, filtros e buscas.

Validação de dados com Zod

Validação de dados com Zod - imagem ilustrativa
Validação de dados com Zod

Confiar nos dados que chegam pelo cliente é um erro clássico. Mesmo que o front-end valide os campos antes de enviar, alguém pode chamar a API diretamente com dados inválidos, maliciosos ou fora do formato esperado. Por isso, validar no servidor é essencial.

Uma das bibliotecas mais usadas para isso no ecossistema JavaScript é o Zod. Com ele, você define um esquema (schema) e valida os dados automaticamente, recebendo erros detalhados caso algo esteja errado.

// app/api/contato/route.ts
import { NextResponse } from 'next/server';
import { z } from 'zod';

const contatoSchema = z.object({
  nome: z.string().min(2, 'Nome deve ter pelo menos 2 caracteres'),
  email: z.string().email('E-mail inválido'),
  mensagem: z.string().min(10, 'Mensagem deve ter pelo menos 10 caracteres')
});

export async function POST(request: Request) {
  try {
    const corpo = await request.json();
    const dadosValidados = contatoSchema.parse(corpo);

    // A partir daqui, dadosValidados é 100% seguro em tipo e formato
    return NextResponse.json(
      { sucesso: true, dados: dadosValidados },
      { status: 201 }
    );
  } catch (erro) {
    if (erro instanceof z.ZodError) {
      return NextResponse.json(
        { erro: 'Dados inválidos', detalhes: erro.flatten() },
        { status: 400 }
      );
    }

    return NextResponse.json(
      { erro: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

Com o Zod, você elimina grande parte dos erros causados por dados malformados e ainda ganha autocompletar no TypeScript, já que os tipos são inferidos a partir do esquema.

Boas práticas de segurança

API Routes ficam expostas na internet, então algumas precauções são obrigatórias para evitar dor de cabeça.

Nunca confie na origem da requisição

Valide sempre o método HTTP, o corpo, os parâmetros e os cabeçalhos. Use bibliotecas como Zod, Yup ou Joi para garantir que os dados estão no formato esperado antes de processá-los.

Use variáveis de ambiente para segredos

Chaves de API, credenciais de banco de dados e tokens de serviços externos jamais devem ficar no código. Use o arquivo .env.local (que não vai para o repositório) e acesse os valores com process.env.NOME_DA_VARIAVEL.

Implemente rate limiting

Sem limite de requisições, um atacante pode bombardear sua API e causar indisponibilidade ou custos altos em serviços externos. Existem middlewares prontos no Next.js e bibliotecas específicas como @upstash/ratelimit e next-rate-limit que resolvem isso em poucas linhas.

Configure CORS com cuidado

Por padrão, API Routes do Next.js respondem a qualquer origem. Se a API for usada apenas pelo seu próprio site, isso não é problema. Mas se for consumida por outros domínios, configure cabeçalhos CORS explicitamente, permitindo apenas as origens confiáveis.

Adicione autenticação quando necessário

Endpoints que manipulam dados sensíveis ou fazem alterações no banco precisam de autenticação. As abordagens mais comuns são JWT (JSON Web Token), sessões via cookie e integração com provedores como Auth0, Clerk ou NextAuth (Auth.js). Nunca exponha dados de outros usuários sem checar quem está pedindo.

Cuidado com exposição de erros detalhados

Em ambiente de produção, evite devolver mensagens de erro completas, que podem revelar estrutura interna do banco ou do código. Log os detalhes no servidor (com ferramentas como Sentry ou LogRocket) e devolva ao cliente apenas uma mensagem genérica.

API Routes vs Server Actions: qual usar?

Com o Next.js 13.4+, surgiu uma nova forma de executar código no servidor sem criar uma rota HTTP: as Server Actions. Elas permitem chamar funções diretamente de componentes, formulários e eventos, sem precisar fazer fetch para uma URL.

A escolha entre uma e outra depende do cenário:

Critério API Routes Server Actions
Exposição externa Sim, qualquer cliente pode chamar Não, é interno ao Next.js
Formulários HTML tradicionais Funciona com fetch manual Funciona nativamente com <form action={...}>
Cacheamento HTTP Sim, com cabeçalhos e fetch Limitado
Streaming de resposta Suportado Suportado
Ideal para integrações externas Sim Não
Ideal para mutações no próprio app Sim, mas com mais código Sim, com menos código

Em resumo: use API Routes quando precisar expor a funcionalidade para clientes externos (apps mobile, outros sistemas, webhooks). Use Server Actions quando a lógica for usada apenas dentro do seu próprio aplicativo Next.js, especialmente em mutações disparadas por interação do usuário.

Middleware e runtime

O Next.js permite configurar o comportamento das rotas com dois recursos importantes: middleware e configuração de runtime.

Middleware

O middleware fica no arquivo middleware.ts na raiz do projeto e intercepta todas as requisições antes de chegarem às rotas. É útil para autenticação, redirecionamentos, cabeçalhos personalizados, A/B testing e logs.

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // Exemplo: bloquear API se não houver token
  if (request.nextUrl.pathname.startsWith('/api/privada')) {
    const token = request.headers.get('authorization');
    if (!token) {
      return NextResponse.json(
        { erro: 'Não autorizado' },
        { status: 401 }
      );
    }
  }

  return NextResponse.next();
}

export const config = {
  matcher: '/api/:path*'
};

Edge vs Node.js Runtime

Por padrão, as API Routes rodam no runtime Node.js. Você pode mudar para o Edge Runtime adicionando uma exportação no arquivo da rota, o que traz execução mais rápida em regiões geográficas próximas do usuário, mas com algumas limitações (como ausência de certas APIs do Node).

// app/api/hora/route.ts
export const runtime = 'edge';

export async function GET() {
  return Response.json({ horario: new Date().toISOString() });
}

Use edge quando precisar de baixa latência e a lógica for simples. Use node quando precisar de integrações com bancos de dados tradicionais, sistemas de arquivos ou bibliotecas pesadas.

Como organizar rotas em projetos maiores

Em projetos pequenos, deixar todas as rotas em app/api funciona bem. Mas conforme o app cresce, vale criar uma estrutura mais clara. Algumas convenções comuns:

  • Agrupar rotas por domínio: app/api/usuarios, app/api/produtos, app/api/pedidos.
  • Separar handlers por recurso dentro de cada pasta: app/api/usuarios/[id]/route.ts, app/api/usuarios/[id]/comentarios/route.ts.
  • Mover lógica de negócio para uma pasta lib/ ou services/ e importar nos handlers.
  • Centralizar validações em lib/schemas.
  • Centralizar acesso a banco em lib/db.

Esse padrão deixa os arquivos de rota enxutos, apenas com a lógica de receber, validar, chamar o serviço e responder.

Erros comuns ao criar API Routes

Alguns tropeços aparecem com frequência, especialmente em quem está começando. Vale a pena conhecer para evitar:

  • Esquecer de exportar a função com o nome do método HTTP em maiúsculas. Sem isso.
  • a rota não responde.
  • Misturar page.tsx e route.ts na mesma pasta. Cada pasta deve ter apenas um tipo de arquivo.
  • Não tratar erros com try/catch. Uma exceção não tratada derruba a resposta e devolve um 500 genérico.
  • Expor mensagens de erro internas em produção. Isso vaza informações sensíveis.
  • Esquecer de validar dados e confiar no front-end. Sempre valide no servidor.
  • Não limitar o tamanho do corpo da requisição. Em APIs que recebem uploads.
  • defina limites para evitar abuso.

Com esses cuidados, a chance de problemas diminui bastante.

Exemplo completo: API de tarefas (to-do)

Para fechar com algo prático, veja um exemplo de API de lista de tarefas usando memória local (você pode substituir por banco de dados depois).

// app/api/tarefas/route.ts
import { NextResponse } from 'next/server';
import { z } from 'zod';

type Tarefa = {
  id: string;
  titulo: string;
  concluida: boolean;
  criadaEm: string;
};

const tarefas: Tarefa[] = [];

const tarefaSchema = z.object({
  titulo: z.string().min(1, 'Título é obrigatório')
});

export async function GET() {
  return NextResponse.json({ tarefas });
}

export async function POST(request: Request) {
  try {
    const corpo = await request.json();
    const { titulo } = tarefaSchema.parse(corpo);

    const novaTarefa: Tarefa = {
      id: crypto.randomUUID(),
      titulo,
      concluida: false,
      criadaEm: new Date().toISOString()
    };

    tarefas.push(novaTarefa);
    return NextResponse.json({ tarefa: novaTarefa }, { status: 201 });
  } catch (erro) {
    if (erro instanceof z.ZodError) {
      return NextResponse.json(
        { erro: 'Dados inválidos', detalhes: erro.flatten() },
        { status: 400 }
      );
    }
    return NextResponse.json(
      { erro: 'Erro interno' },
      { status: 500 }
    );
  }
}

E para alternar entre concluída e pendente:

// app/api/tarefas/[id]/route.ts
import { NextResponse } from 'next/server';

const tarefas: { id: string; titulo: string; concluida: boolean; criadaEm: string }[] = [];

export async function PATCH(
  request: Request,
  { params }: { params: { id: string } }
) {
  const tarefa = tarefas.find(t => t.id === params.id);

  if (!tarefa) {
    return NextResponse.json(
      { erro: 'Tarefa não encontrada' },
      { status: 404 }
    );
  }

  tarefa.concluida = !tarefa.concluida;
  return NextResponse.json({ tarefa });
}

Esse exemplo mostra GET (listar), POST (criar) e PATCH (atualizar parcial) em arquivos separados, respeitando a estrutura do App Router.

Perguntas Frequentes (FAQ)

API Routes substituem um backend completo?

Não. API Routes são ideais para endpoints pequenos e médios, como formulários, webhooks e integrações pontuais. Para sistemas maiores, com autenticação avançada, filas, microserviços ou regras de negócio complexas, o ideal é manter um backend dedicado. Usar API Routes como se fosse um backend completo costuma gerar acoplamento e dificuldade de escalar.

Qual a diferença entre API Routes e Route Handlers?

Nenhuma, na prática. "Route Handlers" é o nome técnico usado pela documentação do Next.js a partir do App Router para se referir às API Routes da nova arquitetura. Se você vir os dois termos, pode tratar como sinônimos.

Posso usar API Routes com banco de dados?

Sim, e é um dos usos mais comuns. Você pode conectar com qualquer banco que tenha driver para Node.js, como PostgreSQL (com Prisma, Drizzle ou pg), MySQL, MongoDB, SQLite e até bancos serverless como Supabase, Neon e PlanetScale. Basta criar a conexão em um arquivo de serviço e importar nas rotas.

API Routes funcionam em deploy na Vercel?

Sim, funcionam nativamente, com suporte a edge runtime e node runtime. Em outros provedores como AWS Amplify, Netlify, Cloudflare Pages e Railway, o suporte também existe, mas vale conferir a documentação específica de cada um para garantir compatibilidade com a versão do Next.js utilizada.

Posso chamar uma API Route dentro de outra API Route?

Tecnicamente dá, mas é um anti-padrão. O ideal é extrair a lógica compartilhada para uma função em lib/ e chamar diretamente nas duas rotas. Isso evita latência extra, complexidade desnecessária e problemas de cache.

Conclusão

API Routes no Next.js são uma das ferramentas mais úteis para quem quer resolver problemas reais de forma rápida e organizada. Com poucos arquivos, você transforma um projeto que antes era só front-end em um sistema completo capaz de receber dados, integrar com serviços externos e servir JSON para front-end, mobile ou outros sistemas.

O segredo é começar pelo simples: uma rota GET que devolve uma data, depois um POST que recebe dados de formulário, em seguida validação com Zod, autenticação quando necessário, e organização por domínio. Cada etapa adiciona robustez sem complicar demais.

Lembre-se também de avaliar se o cenário realmente pede uma API Route ou se uma Server Action resolve com menos código. As duas abordagens se complementam e saber quando usar cada uma é parte do domínio da ferramenta.

Se você precisa de ajuda para colocar isso em prática em um projeto real, a Baita Site tem uma equipe especializada em sites, e-commerce, sistemas e inteligência artificial, com domínio total de WordPress e do ecossistema Next.js. Fale com a gente e veja como podemos acelerar o seu projeto.

Referências consultadas, Documentação oficial do Next.js sobre Route Handlers. Disponível em

https://nextjs.org/docs/app/building-your-application/routing/route-handlers, Documentação oficial do Next.js sobre App Router. Disponível em: https://nextjs.org/docs/app, Documentação oficial do Zod para validação de esquemas. Disponível em: https://zod.dev, Artigo "Next.js API Routes vs Server Actions" do blog da Vercel. Disponível em: https://vercel.com/blog/next-js-api-routes-vs-server-actions, Conteúdo da Rocketseat sobre Next.js 14 e API Routes. Disponível em: https://www.rocketseat.com.br/blog/next-js

Este conteúdo tem caráter informativo. Decisões técnicas devem ser tomadas com profissional especializado.

Quer ajuda para colocar isso em pratica?

A Baita Site trabalha com sites, e-commerce, sistemas e IA. Quem prefere resolver com acompanhamento, sem ter que virar especialista em tudo, costuma procurar esse tipo de suporte.

WhatsApp (47) 99905-6989  |  WhatsApp (47) 99198-5289

Veja tambem

Perguntas Frequentes (FAQ)

1. API Routes substituem um backend completo?

Não. API Routes são ideais para endpoints pequenos e médios, como formulários, webhooks e integrações pontuais. Para sistemas maiores, com autenticação avançada, filas, microserviços ou regras de negócio complexas, o ideal é manter um backend dedicado, em Node.js com NestJS, Python com Django ou outra tecnologia apropriada.

2. Qual a diferença entre API Routes e Route Handlers?

Nenhuma diferença prática. Route Handlers é o nome técnico usado pela documentação do Next.js a partir do App Router para se referir às API Routes da nova arquitetura. Se você vir os dois termos, pode tratar como sinônimos.

3. Posso usar API Routes com banco de dados?

Sim, é um dos usos mais comuns. Você pode conectar com qualquer banco que tenha driver para Node.js, como PostgreSQL com Prisma ou Drizzle, MySQL, MongoDB, SQLite e também bancos serverless como Supabase, Neon e PlanetScale.

4. API Routes funcionam em deploy na Vercel?

Sim, funcionam nativamente, com suporte a edge runtime e node runtime. Em outros provedores como AWS Amplify, Netlify, Cloudflare Pages e Railway, o suporte também existe, mas vale conferir a documentação específica de cada um para garantir compatibilidade.

5. Posso chamar uma API Route dentro de outra API Route?

Tecnicamente dá, mas é um anti-padrão. O ideal é extrair a lógica compartilhada para uma função em uma pasta lib e chamar diretamente nas duas rotas, evitando latência extra e complexidade desnecessária.

Gostaria de receber mais novidades?

Nossas publicações serão sempre voltadas ao mundo do marketing digital, design e criação de sites. Você não será importunado com assuntos que não são do seu interesse!

Compartilhe com seus familiáres e amigos!

Baita Site

Desenvolvemos soluções completas em Marketing Digital para o seu o seu negócio.

Contate-nos, solicite um orçamento, teremos o maior prazer em lhe ajudar!

baitasite@baitasite.com.br
+55 (47) 3360-7843
CNPJ 22.130.607/0001-29

Porque nos escolher?

É algo muito simples! Temos anos e uma vasta experiência com internet, nosso preço é justo e nosso trabalho profissional.

São anos de estudo e dedicação para adquirir o conhecimento necessário para executar projetos com qualidade e eficiência

Onde Estamos

Estamos localizados em um aconchegante home office em Itapema, litoral de Santa Catarina. Você está longe? Não tem problema!

Somos feras em atendimento e suporte a distância, por WhatsApp e pela internet!

Copyright 2020 - Baita Site - Criação de Sites em Itapema. Site feito com amor por nós mesmos!