Eu estava desenvolvendo o BibleFlix — um app de leitura bíblica com estudo por IA. O app é React Native com Expo, roda offline pra leitura normal, e quando o usuário pede um estudo aprofundado de uma passagem, chama o Gemini via OpenRouter pra gerar uma análise teológica completa.
O problema apareceu rápido: eu precisava de uma API key pra chamar o OpenRouter. E essa key estava hardcoded no código do app.
// AIService.ts — o que NUNCA deveria existir em produção
function resolveApiKey(): string {
return (
fromExpo ||
fromNode ||
'sk-or-v1-51219c47c368090c2f7...' // 🔴 isso aqui
);
}
Qualquer pessoa com o APK na mão consegue extrair essa string em 30 segundos com um strings bibleflix.apk | grep sk-or. Pior: se alguém usa essa key, eu pago a conta.
O reflexo de dev backend: "preciso de um servidor"
Minha primeira reação foi a de sempre — subir uma API. Laravel, Express, FastAPI, tanto faz. Um endpoint /api/study que recebe o request, chama o OpenRouter com a key guardada no .env, e devolve o resultado.
Funciona? Funciona. Mas pra um app que precisa de um único endpoint, isso significa:
- Servidor rodando 24/7 (custo)
- Nginx + PHP-FPM ou Node.js (manutenção)
- SSL, firewall, updates de segurança (responsabilidade)
- Monitoramento, logs, backup (operação)
Eu já gerencio 5 projetos em produção num servidor. Não precisava de mais um.
A sacada: eu não preciso de um backend — preciso de um proxy
O que o app realmente precisa é simples:
- Receber um request do app
- Adicionar a API key (que o app não pode saber)
- Repassar pro OpenRouter
- Devolver a resposta
Isso é um proxy. E pra proxy, existe uma solução perfeita: edge functions.
Cloudflare Workers: o backend de 3 arquivos
Um Cloudflare Worker é uma função JavaScript que roda na edge da Cloudflare — em mais de 300 datacenters pelo mundo. O request do usuário em São Paulo é processado no datacenter de São Paulo. Latência mínima.
A estrutura é ridiculamente simples:
bibleflix-worker/
├── wrangler.toml
├── src/
│ └── index.ts
└── package.json
O wrangler.toml configura o projeto:
name = "bibleflix-ai-proxy"
main = "src/index.ts"
compatibility_date = "2024-12-01"
[vars]
ALLOWED_ORIGIN = "https://bibleflix.app"
E o worker em si tem menos de 50 linhas:
// src/index.ts
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// CORS
if (request.method === "OPTIONS") {
return new Response(null, {
headers: {
"Access-Control-Allow-Origin": env.ALLOWED_ORIGIN,
"Access-Control-Allow-Methods": "POST",
"Access-Control-Allow-Headers": "Content-Type",
},
});
}
if (request.method !== "POST") {
return new Response("Method not allowed", { status: 405 });
}
const body = await request.json();
// Repassa pro OpenRouter com a key secreta
const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${env.OPENROUTER_API_KEY}`,
"HTTP-Referer": "https://bibleflix.app",
"X-Title": "BibleFlix",
},
body: JSON.stringify(body),
});
return new Response(response.body, {
status: response.status,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": env.ALLOWED_ORIGIN,
},
});
},
};
A API key fica guardada como secret no Cloudflare:
npx wrangler secret put OPENROUTER_API_KEY
# cola a key, ela é encriptada e nunca aparece em logs
Deploy:
npx wrangler deploy
# Pronto. URL: https://bibleflix-ai-proxy.billy.workers.dev
No app, a mudança é cirúrgica — trocar a URL e remover a key:
// Antes (inseguro)
const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
headers: { "Authorization": `Bearer ${API_KEY}` }, // key exposta
body: JSON.stringify(payload),
});
// Depois (seguro)
const response = await fetch("https://bibleflix-ai-proxy.billy.workers.dev", {
body: JSON.stringify(payload), // sem key, sem header de auth
});
O app nunca mais vê a API key. O Worker é o único que sabe.
Por que Cloudflare Workers e não outra coisa?
Pesquisei as alternativas. Aqui está o que encontrei:
| Plataforma | Free Tier | Latência | Secrets | Ideal para |
|---|---|---|---|---|
| Cloudflare Workers | 100k req/dia | ~1ms (edge) | Encriptados | Proxy, API leve |
| Vercel Functions | 100GB-hrs/mês | ~50ms (serverless) | Env vars | Apps Next.js |
| AWS Lambda | 1M req/mês | ~100ms (cold start) | Env vars / Secrets Manager | Backend completo |
| Supabase Edge | 500k req/mês | ~5ms (Deno) | Vault | Apps com Supabase DB |
| Deno Deploy | 1M req/mês | ~5ms | Env vars | APIs Deno/TS |
| Firebase Functions | 125k req/mês | ~200ms (cold start) | Firebase config | Ecossistema Google |
| Netlify Functions | 125k req/mês | ~50ms | Env vars | Sites Netlify |
Cloudflare ganhou por três motivos:
- 100 mil requests por dia de graça. O BibleFlix não vai chegar nisso tão cedo.
- Zero cold start. Workers rodam em V8 isolates, não em containers. Não existe aquele delay de 200ms+ da primeira chamada.
- Já uso Cloudflare. DNS, R2, o domínio já está lá. Um
wrangler deploye acabou.
Quando esse padrão funciona (e quando não funciona)
Esse padrão de "app + edge function como proxy" funciona perfeitamente quando:
- Seu app precisa chamar APIs externas com keys secretas
- Você não precisa de banco de dados próprio (ou usa algo como Supabase/Firebase)
- O volume de requests cabe no free tier
- Você quer latência mínima sem gerenciar servidor
Não funciona quando:
- Você precisa de lógica de negócio complexa (autenticação, filas, cron jobs)
- Precisa de banco relacional com queries elaboradas
- Tem workers de background ou processos longos
- Precisa de um ecossistema completo (auth + DB + storage + functions)
Pra esse último caso, Firebase ou Supabase fazem mais sentido como BaaS completo. Mas se tudo que você precisa é um proxy seguro entre seu app e uma API de IA, um Worker de 50 linhas resolve.
O que aprendi
A tendência de dev backend é resolver tudo com servidor. É o que sabemos fazer. Mas pra muitos apps — especialmente os que só consomem APIs de IA — você está pagando hosting, configurando Nginx e mantendo SSL pra algo que uma função serverless faz melhor, mais rápido e de graça.
O BibleFlix tem zero backend. Os dados bíblicos são JSON local no app. O estudo por IA passa por um Worker de 50 linhas. O app inteiro custa zero de infraestrutura.
Se você está construindo algo que chama APIs de IA e está pensando em subir um servidor só pra isso, para. Dá uma olhada em Cloudflare Workers. Em 10 minutos você tem um proxy seguro no ar.
E se quiser entender mais sobre como ferramentas como MCP e Claude Code estão mudando a forma como devs constroem e operam software, esses posts dão um bom contexto.