Cloudflare Pages: uma API mínima com a pasta functions

Precisei de dois endpoints pra um protótipo. Em vez de criar um Worker separado, descobri que o Pages tem API embutida por convenção de pasta — em minutos.

O problema

Eu estava criando um protótipo — ou seja, uma versão inicial e simples — de um simulador de provas. O frontend (a parte visual do site, feita em HTML e JavaScript) era estático, o que significa que as páginas não mudam sozinhos e não usam nenhuma ferramenta pesada (como um framework).

No entanto, eu precisava de duas funcionalidades de backend (a parte interna do sistema, que roda no servidor e o usuário não vê): duas portas de entrada (chamadas de endpoints), uma para gravar o feedback do usuário e outra para disparar um e-mail.

Em um ambiente de desenvolvimento tradicional usando Node.js (um ambiente que executa JavaScript no servidor), o caminho normal seria criar um servidor básico usando uma biblioteca chamada Express. Já na Cloudflare (uma plataforma de hospedagem na nuvem), dá uma vontade gigante de criar um Worker separado — que é um pequeno serviço só para rodar esse código de backend. Só que, para apenas duas portinhas (endpoints), configurar um Worker inteiro, definir rotas e lidar com CORS (as regras de segurança que autorizam a troca de dados no navegador) é um exagero imenso — como usar um canhão para acertar um passarinho.

Foi aí que descobri algo que muita gente deixa passar: o Cloudflare Pages tem capacidades de API embutidas, baseadas em “convenção de pastas” (ou seja, você só precisa organizar os arquivos do jeito certo que o sistema entende tudo sozinho). Não é preciso criar um Worker separado: o próprio projeto no Pages entrega as páginas estáticas e os endpoints da API ao mesmo tempo.

Este artigo é um resumo do que aprendi para que, da próxima vez que você precisar de “dois endpoints rápidos”, não precise montar uma infraestrutura inteira do zero.

A divisão que confunde

Primeiro, vale entender por que existem dois produtos na Cloudflare. Eles se dividem assim:

  • Workers — Focados em backend e APIs (sistemas que fazem pontes de comunicação entre aplicações). Nele, você escreve um organizador de tráfego (um roteador customizado) que direciona tudo o que chega.
  • Pages — Focado em hospedar a parte estática (arquivos HTML, CSS ou o resultado final do código de React, Vue ou Astro).

A confusão acontece porque o Pages também consegue servir uma API, mas faz isso usando uma regra diferente. Em vez de você programar um controle geral de requisições (um handler fetch global), você simplesmente cria uma pasta e dá aos arquivos os nomes das rotas que deseja atender. É menos flexível que um Worker completo, mas exige zero configuração para casos simples.

A convenção da pasta functions

Se você já tem uma pasta onde ficam seus arquivos estáticos (geralmente chamada de public/ ou dist/), basta criar uma pasta chamada functions/ ao lado dela. O Wrangler (a ferramenta de linha de comando da Cloudflare) varre essa pasta durante o envio do projeto e transforma automaticamente cada arquivo .js em uma rota de API.

O mapeamento da URL funciona diretamente pelo nome e caminho do arquivo:

Arquivo URL que atende
functions/api/feedback.js /api/feedback
functions/api/hello.js /api/hello
functions/api/users/[id].js /api/users/:id

Você não precisa de ferramentas extras como o itty-router nem precisa configurar intermediários (middlewares). O próprio nome do arquivo já é o endereço da rota.

O código mínimo

Dentro da pasta functions/, o seu arquivo precisa apenas exportar funções com nomes padrão dos métodos HTTP — como onRequestGet (para ler dados) ou onRequestPost (para enviar dados):

// functions/api/hello.js
export async function onRequestGet({ request, env }) {
  // Lê query param (?nome=Joao)
  const url = new URL(request.url);
  const nome = url.searchParams.get("nome") || "Visitante";

  return Response.json({
    mensagem: `Olá ${nome}!`,
    timestamp: Date.now(),
  });
}

Isso é tudo. Quando o projeto estiver publicado, acessar /api/hello?nome=Tiago vai devolver a resposta {"mensagem":"Olá Tiago!","timestamp":...}.

Se você precisar tratar o envio de formulários (POST), usa onRequestPost. Para deletar algo (DELETE), usa onRequestDelete. Você só escreve e exporta a função que realmente for usar.

O argumento env dentro da função te dá acesso aos bindings — que são as conexões com bancos de dados (como KV e D1) e chaves secretas (secrets) da Cloudflare —, exatamente igual a um Worker tradicional. Então, para salvar um feedback em um banco KV, o código todo ocupa cerca de 6 linhas.

O deploy

O processo de deploy (enviar seu código do computador para a nuvem) é totalmente cuidado pelo Wrangler. Você aponta o comando para a pasta de arquivos estáticos, ele percebe a pasta functions/ vizinha e integra tudo automaticamente:

npx wrangler pages deploy ./dist --project-name meu-site-rapido

Não precisa de nenhuma configuração adicional nem de um arquivo global de rotas. O mesmo comando de deploy que coloca seu HTML no ar também coloca sua API funcionando.

Quando usar Pages Functions vs Worker

Esta é a dúvida mais comum. A regra prática que guardei para mim é a seguinte:

  • Use Pages Functions quando você tem um site estático que precisa de apenas alguns endpoints auxiliares — como salvar um feedback, enviar um e-mail ou consultar um dado secreto. O trabalho de configuração é zero.
  • Use um Worker separado quando a API for o produto principal (muitas rotas, lógica complexa, rotas personalizadas e regras intermediárias). O Pages Functions começa a ficar incômodo e difícil de organizar quando você tem mais de 20 endpoints.

O critério não é o “tamanho do código”, mas sim a pergunta: “a API é a coadjuvante ou a protagonista do projeto?”.

No meu protótipo, a API era coadjuvante (só servia para gravar o feedback), então o Pages Functions serviu perfeitamente. Já no AeroLog (este blog), a API de administração é a protagonista — por isso, fez sentido usar um Worker separado.

O que aprendi

A lição que fica para além deste caso é: antes de começar a montar uma grande infraestrutura, pergunte se a plataforma já não resolve o seu problema através de regras simples de convenção. Eu quase criei um Worker do zero, configurando rotas, CORS e um deploy separado só para dois endpoints. Seriam 30 minutos de trabalho manual que viraram 5 minutos quando descobri que o Pages já tinha essa função embutida. Esse tipo de convenção parece “mágica” no bom sentido: elimina linhas de código que você teria que escrever e manter.

E o segundo aprendizado mais amplo: quando existem “dois produtos que parecem fazer a mesma coisa”, não significa que você deve escolher o “melhor”, mas sim “o mais adequado para o seu caso”. Os Workers e o Pages Functions têm capacidades parecidas, mas cada um brilha em um cenário diferente. Conhecer as duas ferramentas permite que você faça uma escolha consciente em vez de improvisar.

Leia também

Comentários

Carregando comentários…

Deixe um comentário