{
  "id": "build-a-cloudflare-worker-api-proxy",
  "type": "prompts",
  "category": "prompts",
  "locale": "fr",
  "url": "/fr/prompts/build-a-cloudflare-worker-api-proxy",
  "title": "Prompt pour construire un proxy API Cloudflare Worker",
  "description": "Copiez-collez un prompt IA pour construire un Cloudflare Worker qui proxy et limite le débit des appels API externes, ajoute des en-têtes d'authentification et met en cache les réponses.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "Cloudflare",
    "TypeScript"
  ],
  "tags": [
    "cloudflare",
    "typescript",
    "security",
    "deploy"
  ],
  "difficulty": "medium",
  "updated": "2026-06-08",
  "markdown": "Utilisez ce prompt pour construire un Cloudflare Worker qui se place devant une API externe,\ninjecte des en-têtes d'authentification, limite le débit par IP avec Workers KV,\net met en cache les réponses — afin que les clients ne voient jamais votre clé API amont.\n\n## Prompt principal\n\n```txt title=\"Main Prompt\"\nYou are building a Cloudflare Worker using TypeScript and the Workers runtime (not Node.js).\nThe Worker will proxy requests to an upstream API (e.g., OpenAI at https://api.openai.com).\n\nTask: create a production-ready API proxy Worker.\n\nRequirements:\n- Use `wrangler` v3 for local dev. Scaffold with `bun create cloudflare@latest` and choose\n  \"Hello World\" Worker with TypeScript.\n- Upstream URL: read from a Wrangler secret `UPSTREAM_URL` (string).\n- Auth: inject `Authorization: Bearer ${env.UPSTREAM_API_KEY}` on every proxied request,\n  where `UPSTREAM_API_KEY` is a Wrangler secret. Never expose this header to the client.\n- CORS: allow only origins in `env.ALLOWED_ORIGINS` (comma-separated string secret).\n  Return a `403` for disallowed origins. Handle preflight OPTIONS requests.\n- Rate limiting: use Workers KV binding `RATE_LIMIT_KV`.\n  - Key: `rl:${ip}` where ip is `request.headers.get('CF-Connecting-IP')`.\n  - Value: request count for the current UTC minute (TTL = 60 s).\n  - Limit: 60 requests/minute per IP. Return `429` with `Retry-After: 60` if exceeded.\n- Caching: for GET requests, check `caches.default` before proxying upstream. Cache\n  successful responses with `Cache-Control: public, max-age=300`.\n- Strip the following headers from the upstream response before returning to the client:\n  `x-powered-by`, `server`, `cf-ray`.\n- Wrangler config: declare the KV namespace binding and all secrets in `wrangler.toml`.\n- Do NOT use Node.js APIs (`fs`, `path`, `Buffer`) — Workers runtime only.\n\nStop and list all planned files before writing code.\n```\n\n## Notes d'implémentation\n\n- Les Cloudflare Workers reçoivent une `Request` et retournent une `Response` — évitez les motifs de type `express`.\n- `caches.default` est le cache edge de Cloudflare ; il fonctionne uniquement en production. Utilisez `MINIFLARE_CACHE`\n  pour les tests en développement local ou simulez le cache.\n- `CF-Connecting-IP` est injecté par Cloudflare — il n'est pas falsifiable depuis l'internet public, mais\n  testez localement avec une IP de repli codée en dur.\n- Les secrets Wrangler sont définis avec `wrangler secret put UPSTREAM_API_KEY` — ne les stockez jamais dans\n  `wrangler.toml` ou dans des fichiers `.env` commités.\n\n## Modifications de fichiers attendues\n\n```txt\nwrangler.toml                  (new)\nsrc/index.ts                   (new — Worker entrypoint)\nsrc/cors.ts                    (new — CORS helper)\nsrc/rate-limit.ts              (new — KV rate limiter)\npackage.json                   (new)\ntsconfig.json                  (new)\n.dev.vars                      (new — local dev secrets, gitignored)\n.gitignore                     (edited — add .dev.vars)\n```\n\n## Critères d'acceptation\n\n- `wrangler dev` démarre sans erreur et transmet un `GET /` vers l'URL amont.\n- Une IP envoyant 61 requêtes en une minute reçoit un code `429` à la 61e requête.\n- Une requête provenant d'une origine non autorisée reçoit un code `403`.\n- L'en-tête `Authorization` n'apparaît pas dans la réponse ni dans aucun en-tête visible par le client.\n- `wrangler deploy` réussit et le Worker est actif sur `workers.dev`.\n\n## Commandes de test\n\n```bash\nwrangler dev &\n# test normal proxy\ncurl http://localhost:8787/ -H \"Origin: https://myapp.com\"\n# test CORS rejection\ncurl http://localhost:8787/ -H \"Origin: https://evil.com\"\n# test rate limit (requires 61 rapid requests)\nfor i in $(seq 1 62); do curl -s -o /dev/null -w \"%{http_code}\\n\" http://localhost:8787/; done\n```\n\n## Erreurs courantes de l'IA\n\n- Utiliser `process.env` au lieu du paramètre `env` passé au gestionnaire `fetch` du Worker.\n- Oublier de gérer les requêtes préliminaires `OPTIONS`, ce qui casse le CORS pour les appels POST/PUT.\n- Stocker `UPSTREAM_API_KEY` dans `wrangler.toml` comme une variable simple au lieu d'un secret.\n- Utiliser `node:buffer` ou d'autres modules internes de Node.js, qui ne sont pas disponibles dans l'environnement d'exécution des Workers.\n\n## Prompt de correction\n\n```txt title=\"Fix Prompt\"\nThe Worker fails with a runtime error or leaks the API key. Fix in order:\n1. Replace `process.env.X` with `env.X` everywhere — Workers use the `env` handler parameter.\n2. Add an OPTIONS handler before the proxy logic that returns the CORS headers with a 204 status.\n3. Move `UPSTREAM_API_KEY` from `wrangler.toml` [vars] to a secret: `wrangler secret put UPSTREAM_API_KEY`.\nShow only the corrected diff.\n```"
}