Aprenda a usar as Rotas de API do Next.js para construir backends serverless diretamente na sua aplicação Next.js. Este guia cobre tudo, desde a configuração básica até técnicas avançadas para lidar com autenticação, persistência de dados e muito mais.
Rotas de API do Next.js: Construindo seu Backend com Facilidade
O Next.js revolucionou o desenvolvimento front-end com seus recursos poderosos e estrutura intuitiva. Mas você sabia que ele também pode simplificar significativamente o desenvolvimento backend? As Rotas de API do Next.js permitem criar endpoints de API serverless diretamente na sua aplicação Next.js, eliminando a necessidade de um servidor backend separado em muitos casos. Este guia completo irá orientá-lo no processo de construção de um backend robusto e escalável usando as Rotas de API do Next.js.
O que são as Rotas de API do Next.js?
As Rotas de API são funções serverless que você cria no diretório /pages/api
do seu projeto Next.js. Essas funções lidam com requisições HTTP recebidas e retornam respostas, assim como uma API backend tradicional. A principal diferença é que elas são implantadas como funções serverless, o que significa que você não precisa gerenciar servidores ou infraestrutura.
Pense nelas como funções backend leves e sob demanda que são perfeitamente integradas ao seu front-end Next.js.
Benefícios de Usar as Rotas de API do Next.js
- Desenvolvimento Simplificado: Escreva seu código front-end e backend no mesmo projeto, usando JavaScript ou TypeScript. Chega de alternar entre diferentes projetos e tecnologias.
- Arquitetura Serverless: Beneficie-se da escalabilidade, confiabilidade e custo-benefício da computação serverless. Pague apenas pelos recursos que consumir.
- Implantação Fácil: Implante sua aplicação inteira (front-end e backend) com um único comando usando plataformas como Vercel ou Netlify.
- Segurança Integrada: O Next.js e as plataformas serverless fornecem recursos de segurança integrados para proteger seus endpoints de API.
- Desempenho Aprimorado: As Rotas de API podem ser implantadas mais perto de seus usuários, reduzindo a latência e melhorando o desempenho, o que é particularmente benéfico para usuários em todo o mundo.
- Reutilização de Código: Compartilhe código entre seu front-end e backend, reduzindo a duplicação de código e melhorando a manutenibilidade.
Começando com as Rotas de API do Next.js
Vamos criar uma rota de API simples que retorna uma resposta JSON. Primeiro, certifique-se de que você tem um projeto Next.js configurado. Se não, crie um usando:
npx create-next-app my-app
cd my-app
Agora, crie um arquivo chamado hello.js
dentro do diretório /pages/api
:
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}
Este código define uma rota de API simples que responde com um objeto JSON contendo o nome "John Doe". Para acessar esta rota de API, inicie seu servidor de desenvolvimento Next.js:
npm run dev
Em seguida, abra seu navegador e navegue para http://localhost:3000/api/hello
. Você deverá ver a seguinte resposta JSON:
{"name": "John Doe"}
Entendendo o Manipulador da Rota de API
A função handler
na sua rota de API recebe dois argumentos:
req
: Uma instância dehttp.IncomingMessage
, que contém informações sobre a requisição recebida, como o método da requisição, cabeçalhos e corpo.res
: Uma instância dehttp.ServerResponse
, que permite enviar uma resposta de volta ao cliente.
Você pode usar esses objetos para lidar com diferentes tipos de requisições, ler dados do corpo da requisição, definir cabeçalhos de resposta e enviar diferentes tipos de respostas.
Lidando com Diferentes Métodos HTTP
Você pode usar a propriedade req.method
para determinar o método HTTP da requisição recebida e lidar com diferentes métodos de acordo. Por exemplo:
// pages/api/method.js
export default function handler(req, res) {
if (req.method === 'GET') {
// Lida com a requisição GET
res.status(200).json({ message: 'Esta é uma requisição GET' })
} else if (req.method === 'POST') {
// Lida com a requisição POST
res.status(200).json({ message: 'Esta é uma requisição POST' })
} else {
// Lida com outros métodos
res.status(405).json({ message: 'Método Não Permitido' })
}
}
Neste exemplo, a rota de API lida com requisições GET e POST. Se o método da requisição for GET, ela responde com um objeto JSON contendo a mensagem "Esta é uma requisição GET". Se o método for POST, responde com um objeto JSON contendo a mensagem "Esta é uma requisição POST". Se o método da requisição for qualquer outro, ela responde com um erro 405 Método Não Permitido.
Lendo Dados do Corpo da Requisição
Para requisições POST, PUT e PATCH, você frequentemente precisa ler dados do corpo da requisição. O Next.js fornece suporte integrado para analisar corpos de requisição JSON e codificados por URL. Para analisar um corpo de requisição JSON, você pode usar a propriedade req.body
. Por exemplo:
// pages/api/post.js
export default async function handler(req, res) {
if (req.method === 'POST') {
const { name, email } = req.body
// Processa os dados
console.log('Nome:', name)
console.log('Email:', email)
res.status(200).json({ message: 'Dados recebidos com sucesso' })
} else {
res.status(405).json({ message: 'Método Não Permitido' })
}
}
Para testar esta rota de API, você pode usar uma ferramenta como o Postman ou curl para enviar uma requisição POST com um corpo JSON:
curl -X POST -H "Content-Type: application/json" -d '{"name": "Jane Doe", "email": "jane.doe@example.com"}' http://localhost:3000/api/post
Definindo Cabeçalhos de Resposta
Você pode usar o método res.setHeader()
para definir cabeçalhos de resposta. Isso é útil para definir o tipo de conteúdo, controle de cache e outras informações importantes. Por exemplo:
// pages/api/headers.js
export default function handler(req, res) {
res.setHeader('Content-Type', 'application/json')
res.setHeader('Cache-Control', 's-maxage=3600')
res.status(200).json({ message: 'Olá, mundo!' })
}
Neste exemplo, a rota de API define o cabeçalho Content-Type
para application/json
, indicando que a resposta é um objeto JSON. Ela também define o cabeçalho Cache-Control
para s-maxage=3600
, que informa ao navegador e à CDN para armazenar a resposta em cache por até 1 hora.
Tratamento de Erros
É importante tratar os erros de forma elegante em suas rotas de API. Você pode usar blocos try-catch para capturar exceções e enviar respostas de erro apropriadas ao cliente. Por exemplo:
// pages/api/error.js
export default async function handler(req, res) {
try {
// Simula um erro
throw new Error('Algo deu errado')
} catch (error) {
console.error(error)
res.status(500).json({ message: 'Erro Interno do Servidor' })
}
}
Neste exemplo, a rota de API simula um erro lançando um novo objeto Error
. O bloco catch captura o erro, o registra no console e envia uma resposta 500 Erro Interno do Servidor para o cliente. Considere usar um sistema de registro robusto como Sentry ou Datadog para ambientes de produção.
Conectando a um Banco de Dados
Um dos casos de uso mais comuns para rotas de API é a conexão a um banco de dados. As Rotas de API do Next.js se integram perfeitamente com vários bancos de dados, incluindo:
- MongoDB: Um popular banco de dados NoSQL bem adequado para dados flexíveis e não estruturados.
- PostgreSQL: Um poderoso banco de dados relacional de código aberto, conhecido por sua confiabilidade e integridade de dados.
- MySQL: Outro popular banco de dados relacional de código aberto amplamente utilizado para aplicações web.
- Firebase: Uma plataforma baseada em nuvem que fornece um banco de dados em tempo real e outros serviços.
- FaunaDB: Um banco de dados serverless projetado para aplicações globais.
Aqui está um exemplo de como se conectar a um banco de dados MongoDB em uma rota de API do Next.js:
// pages/api/mongodb.js
import { MongoClient } from 'mongodb'
const uri = process.env.MONGODB_URI
const options = {}
let client
let clientPromise
if (!process.env.MONGODB_URI) {
throw new Error('Por favor, adicione sua URI do Mongo ao .env.local')
}
if (process.env.NODE_ENV === 'development') {
// Em modo de desenvolvimento, use uma variável global para que o valor
// seja preservado entre as recargas de módulo causadas pelo HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
// Em modo de produção, é melhor não usar uma variável global.
client = new MongoClient(uri, options)
clientPromise = client.connect()
}
// Exporte uma promessa MongoClient com escopo de módulo. Ao fazer isso em um
// módulo separado, o cliente pode ser reutilizado com segurança em várias
// funções. Veja: https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/lib/mongodb.js
export default async function handler(req, res) {
try {
const client = await clientPromise
const db = client.db(process.env.MONGODB_DB)
const collection = db.collection('users')
const users = await collection.find({}).toArray()
res.status(200).json({ users })
} catch (e) {
console.error(e)
res.status(500).json({ message: 'Falha ao buscar usuários' })
}
}
Antes de executar este código, certifique-se de que você tem o pacote mongodb
instalado:
npm install mongodb
Você também precisa definir as variáveis de ambiente MONGODB_URI
e MONGODB_DB
. Essas variáveis devem ser definidas em seu arquivo .env.local
(ou nas configurações de variáveis de ambiente do seu provedor de hospedagem para produção). A MONGODB_URI
contém a string de conexão para seu banco de dados MongoDB, e MONGODB_DB
especifica o nome do banco de dados.
Autenticação e Autorização
Proteger suas rotas de API é crucial para a segurança. As Rotas de API do Next.js podem ser protegidas usando várias técnicas de autenticação e autorização, incluindo:
- JSON Web Tokens (JWT): Um padrão para transmitir informações de forma segura entre as partes como um objeto JSON.
- Chaves de API: Uma maneira simples de restringir o acesso aos seus endpoints de API.
- OAuth: Um protocolo de delegação que permite que usuários concedam a aplicações de terceiros acesso a seus recursos sem compartilhar suas credenciais.
- NextAuth.js: Uma solução de autenticação de código aberto completa para aplicações Next.js.
Aqui está um exemplo de como proteger uma rota de API usando autenticação JWT:
// pages/api/protected.js
import jwt from 'jsonwebtoken'
const secret = process.env.JWT_SECRET
export default function handler(req, res) {
const token = req.headers.authorization?.split(' ')[1]
if (!token) {
return res.status(401).json({ message: 'Não autorizado' })
}
try {
const decoded = jwt.verify(token, secret)
// O objeto "decoded" contém as informações do usuário embutidas no token
// Por exemplo: const userId = decoded.userId;
// Continua o processamento da requisição
res.status(200).json({ message: 'Recurso protegido acessado com sucesso' })
} catch (error) {
return res.status(401).json({ message: 'Token inválido' })
}
}
Antes de executar este código, certifique-se de que você tem o pacote jsonwebtoken
instalado:
npm install jsonwebtoken
Você também precisa definir a variável de ambiente JWT_SECRET
. Esta deve ser uma chave secreta forte e gerada aleatoriamente, usada para assinar e verificar JWTs. Armazene-a com segurança e nunca a exponha em seu código do lado do cliente.
Middleware
Embora o Next.js não ofereça middleware tradicional para rotas de API da mesma forma que o Express.js, você pode alcançar uma funcionalidade semelhante envolvendo seus manipuladores de rotas de API com funções reutilizáveis. Isso permite que você execute tarefas como:
- Autenticação: Verificar as credenciais do usuário antes de permitir o acesso aos endpoints da API.
- Autorização: Verificar se um usuário tem as permissões necessárias para realizar uma ação específica.
- Registro (Logging): Registrar requisições recebidas e respostas enviadas para fins de auditoria e depuração.
- Validação: Validar os dados da requisição para garantir que atendam a critérios específicos.
- Limitação de Taxa (Rate Limiting): Proteger sua API contra abuso, limitando o número de requisições que um usuário pode fazer em um determinado período de tempo.
Aqui está um exemplo de como criar um middleware de registro simples:
// utils/middleware.js
export function withLogging(handler) {
return async function(req, res) {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`)
return handler(req, res)
}
}
Para usar este middleware, simplesmente envolva seu manipulador de rota de API com a função withLogging
:
// pages/api/logged.js
import { withLogging } from '../../utils/middleware'
async function handler(req, res) {
res.status(200).json({ message: 'Esta requisição foi registrada' })
}
export default withLogging(handler)
Melhores Práticas para Construir Rotas de API no Next.js
- Mantenha suas rotas de API pequenas e focadas. Cada rota de API deve lidar com uma tarefa ou recurso específico.
- Use variáveis de ambiente para dados sensíveis. Nunca codifique segredos ou chaves de API diretamente no seu código.
- Valide os dados da requisição para prevenir vulnerabilidades de segurança. Use uma biblioteca como Joi ou Yup para validar os corpos das requisições.
- Trate os erros de forma elegante e forneça mensagens de erro informativas. Use blocos try-catch e registre os erros em um local centralizado.
- Use cache para melhorar o desempenho. Armazene em cache dados acessados com frequência para reduzir a carga no banco de dados.
- Monitore suas rotas de API em busca de desempenho e erros. Use uma ferramenta de monitoramento como Sentry ou Datadog para acompanhar a saúde da sua API.
- Documente suas rotas de API usando uma ferramenta como Swagger ou OpenAPI. Isso facilita para outros desenvolvedores usarem sua API.
- Considere usar TypeScript para segurança de tipos. O TypeScript pode ajudá-lo a encontrar erros mais cedo e a melhorar a manutenibilidade do seu código.
- Pense em internacionalização (i18n) desde o início. Se sua aplicação será usada por usuários de diferentes países, projete suas rotas de API para suportar múltiplos idiomas e moedas. Por exemplo, endpoints de API para e-commerce podem precisar lidar com diferentes taxas de impostos e custos de envio com base na localização do usuário.
- Implemente uma configuração adequada de CORS (Cross-Origin Resource Sharing). Isso é crucial quando sua API é acessada de um domínio diferente da sua aplicação Next.js. Configure o CORS cuidadosamente para permitir que apenas origens autorizadas acessem os recursos da sua API.
Técnicas Avançadas
Tarefas em Segundo Plano (Background Jobs)
Para tarefas de longa duração que não devem bloquear a resposta da API, considere o uso de tarefas em segundo plano. Você pode usar bibliotecas como BullMQ ou Bree para gerenciar suas tarefas em segundo plano e processá-las de forma assíncrona.
WebSockets
Para aplicações em tempo real, você pode usar WebSockets em suas rotas de API do Next.js. Bibliotecas como Socket.IO e ws facilitam o estabelecimento de conexões persistentes entre o cliente e o servidor.
GraphQL
Se você precisa de uma maneira mais flexível e eficiente de buscar dados, considere usar GraphQL. Você pode usar bibliotecas como Apollo Server ou Yoga para criar um endpoint de API GraphQL em sua aplicação Next.js.
Conclusão
As Rotas de API do Next.js fornecem uma maneira poderosa e conveniente de construir backends serverless diretamente em sua aplicação Next.js. Ao aproveitar os benefícios da arquitetura serverless, você pode simplificar o desenvolvimento, melhorar o desempenho e reduzir custos. Seja construindo um formulário de contato simples ou uma plataforma de e-commerce complexa, as Rotas de API do Next.js podem ajudá-lo a criar um backend robusto e escalável com facilidade. Com uma sólida compreensão dos fundamentos e a aplicação das melhores práticas, você pode aproveitar esta ferramenta poderosa para criar aplicações eficientes, seguras e globalmente acessíveis.