# Cloudflare Workers en frontal d’une API REST multilingue

> Multiplier les entrées de cache par langue pour un même contenu gaspille de la place et complique les invalidations. Un routage à l'edge évite ce piège.

- Auteur : WordPress Développement
- Publié le : 2021-07-18
- Mis à jour le : 2021-07-18
- Catégorie : Headless &amp; API
- URL : https://www.wpmoderne.fr/headless/cloudflare-workers-frontal-api-rest-multilingue/

## L’essentiel

- Router par langue à l'edge évite de dupliquer le cache par erreur
- Le Worker choisit la langue avant même d'atteindre le cache CDN
- L'invalidation reste centralisée sur un seul contenu source

Six langues, un seul contenu source par article, et pourtant jusqu'à dix-huit entrées de cache distinctes pour une même page avant la mise en place d'un routage à l'edge : c'est le chiffre qui a motivé la refonte du frontal Cloudflare devant l'API REST multilingue d'un site institutionnel, hébergé sur WordPress avec Polylang.

Le problème ne venait pas d'un manque de cache, mais de sa fragmentation excessive : chaque combinaison de langue et de variante d'en-tête créait sa propre entrée, sans qu'aucune de ces entrées ne partage la moindre invalidation avec les autres, y compris pour un contenu qui n'avait, au fond, qu'une seule source à invalider.

## Le constat de départ

Le front consommait l'API REST WordPress en passant la langue soit en paramètre de requête, soit en en-tête, selon les équipes qui avaient développé chaque section du site au fil du temps. Résultat : la même ressource, pour la même langue, apparaissait sous plusieurs formes d'URL différentes dans le cache Cloudflare, chacune avec son propre cycle de vie, ses propres invalidations, et donc son propre risque d'incohérence entre langues.

## Objectif : un point de routage unique à l'edge

Plutôt que de laisser chaque équipe front décider comment exprimer la langue dans sa requête, un Cloudflare Worker a été placé en frontal de l'API REST, avec la responsabilité exclusive de déterminer la langue demandée, de la normaliser, puis de construire une clé de cache unique et prévisible pour chaque combinaison ressource/langue — indépendamment de la façon dont le front l'a exprimée à l'origine.

> L'essentiel à retenir : Router par langue à l'edge évite de dupliquer le cache par erreur ; Le Worker choisit la langue avant même d'atteindre le cache CDN ; L'invalidation reste centralisée sur un seul contenu source

## Le Worker de routage

```
addEventListener('fetch', event => {
  event.respondWith(routeRequest(event.request));
});

async function routeRequest(request) {
  const url = new URL(request.url);
  const lang = resolveLang(request, url);

  // Cle de cache normalisee, independante de la maniere dont
  // le front a exprime la langue a l'origine.
  const cacheUrl = new URL(url.origin + url.pathname);
  cacheUrl.searchParams.set('lang', lang);
  const cacheKey = new Request(cacheUrl.toString(), request);

  const cache = caches.default;
  let response = await cache.match(cacheKey);
  if (response) return response;

  const originUrl = new URL(url.origin + url.pathname);
  originUrl.searchParams.set('lang', lang);
  response = await fetch(originUrl.toString(), request);

  response = new Response(response.body, response);
  response.headers.set('Cache-Control', 's-maxage=1800');
  event.waitUntil(cache.put(cacheKey, response.clone()));

  return response;
}

function resolveLang(request, url) {
  return (
    url.searchParams.get('lang') ||
    request.headers.get('x-site-lang') ||
    'fr'
  );
}
```

Quelle que soit la manière dont un front interroge l'API — via un paramètre `lang` historique ou via l'en-tête `X-Site-Lang` plus récent — le Worker fait converger la requête vers une seule et même clé de cache normalisée par langue, éliminant les doublons involontaires.

## Ce que le routage à l'edge apporte

- Une seule entrée de cache par ressource et par langue, quel que soit le front qui interroge l'API.
- Un point unique où faire évoluer la logique de résolution de langue, sans devoir coordonner un changement sur tous les fronts consommateurs.
- Une invalidation de cache plus simple à raisonner : purger une ressource revient à purger ses six variantes de langue prévisibles, plutôt qu'un nombre indéterminé d'entrées héritées de formats d'appel différents.

### La limite de cette approche

Le Worker ne traduit rien lui-même : il ne fait que router et normaliser la clé de cache. Le contenu de chaque langue reste entièrement produit et maintenu côté WordPress, via Polylang ou tout autre système de gestion de contenu multilingue — cette architecture ne dit rien de la façon dont ce contenu est traduit ou synchronisé entre langues.

## Un point d'attention sur l'origine

Le Worker transmet toujours la langue résolue à l'API d'origine sous une forme unique (paramètre `lang`), ce qui simplifie également le code côté WordPress : plus besoin de gérer plusieurs conventions d'appel selon le front, un seul format à traiter côté serveur.

> Un cache fragmenté n'est presque jamais un problème de capacité de stockage : c'est un problème de cohérence, où chaque fragment vit sa vie et peut finir par raconter une version légèrement différente du même contenu.

## En résumé

Ce chantier ne portait pas sur la traduction du contenu, mais sur la mécanique de cache qui l'entoure. En déplaçant la décision de langue à l'edge, avant même que la requête n'atteigne le cache, le nombre d'entrées distinctes pour un même contenu est retombé à son minimum réel : une par langue effectivement gérée, ni plus, ni moins.
