Qu'est-ce que la limitation des requêtes ?
En tant que client de l'API, vous ne pouvez envoyer qu'un nombre limité de requêtes dans une période donnée. Si vous dépassez cette limite :
- Votre requête est rejetée avec le code HTTP 429 Too Many Requests
- Vous recevez des informations sur le temps d'attente avant de pouvoir réessayer
- Les limitations sont les suivantes:
-
- Maximum de 3 points/ seconde
-
- Possibilité de “burst“(dépassement) à 10 temporairement
- 1 point équivaut normalement à 1 requête mais pourra éventuellement changer selon le coût en ressources de certaines requêtes.
- Voir la description de l’algorithme “Leaky Bucket” ici pour plus de détails: https://fr.wikipedia.org/wiki/Seau_perc%C3%A9
Comportements que vous observerez
Requêtes autorisées (sous la limite) :
HTTP/1.1 200 OK
X-Rate-Limit-Remaining: 42
Content-Type: application/json
...
L'en-tête X-Rate-Limit-Remaining indique combien de requêtes vous pouvez encore faire dans la fenêtre temporelle actuelle.
Limite dépassée (HTTP 429) :
HTTP/1.1 429 Too Many Requests
X-Rate-Limit-Retry-After-Milliseconds: 5000
Content-Type: application/json
{"error": "Too many requests"}
En-têtes de réponse à surveiller
- X-Rate-Limit-Remaining : nombre de requêtes restantes avant limitation
- X-Rate-Limit-Retry-After-Milliseconds : millisecondes à attendre avant de réessayer (en cas de 429)
Gestion côté client recommandée
JavaScript (fetch) :
async function appellerAPI(url) {
const response = await fetch(url);
if (response.status === 429) {
const attenteMs = parseInt(response.headers.get('X-Rate-Limit-Retry-After-Milliseconds') || '1000');
console.warn(`Limite atteinte. Attendre ${attenteMs} ms avant de réessayer.`);
await new Promise(resolve => setTimeout(resolve, attenteMs));
return null;
}
const restant = response.headers.get('X-Rate-Limit-Remaining');
console.log(`Requêtes restantes : ${restant}`);
return await response.json();
}
Python (requests) :
import time
import requests
def appeler_api(url):
response = requests.get(url)
if response.status_code == 429:
attente_ms = int(response.headers.get('X-Rate-Limit-Retry-After-Milliseconds', '1000'))
print(f'Limite atteinte. Attente de {attente_ms} ms')
time.sleep(attente_ms / 1000.0)
return None
restant = response.headers.get('X-Rate-Limit-Remaining')
print(f'Requêtes restantes : {restant}')
return response.json()
C# (HttpClient) :
async Task<string> AppelerAPI(string url)
{
using var client = new HttpClient();
var response = await client.GetAsync(url);
if ((int)response.StatusCode == 429)
{
var attenteMsStr = response.Headers.GetValues("X-Rate-Limit-Retry-After-Milliseconds").FirstOrDefault() ?? "1000";
if (int.TryParse(attenteMsStr, out var attentMs))
{
Console.WriteLine($"Limite atteinte. Attente de {attentMs} ms");
await Task.Delay(attentMs);
}
return null;
}
var restant = response.Headers.GetValues("X-Rate-Limit-Remaining").FirstOrDefault();
Console.WriteLine($"Requêtes restantes : {restant}");
return await response.Content.ReadAsStringAsync();
}
Stratégie de retry recommandée
Premier 429 : attendre exactement le délai indiqué
429 répétés : ajouter un délai supplémentaire progressif (backoff exponentiel)
Surveiller X-Rate-Limit-Remaining : si faible (≤ 3), espacer vos appels
Erreurs à éviter
- Ignorer le code 429 et continuer à appeler immédiatement
- Ne pas respecter le délai d'attente indiqué
- Envoyer des rafales de requêtes parallèles qui épuisent instantanément votre quota
- Supposer que la limite est fixe (elle peut changer)
- Mise en cache : éviter les appels redondants
- Espacement : ne pas envoyer toutes vos requêtes d'un coup
- Monitoring : surveiller X-Rate-Limit-Remaining pour anticiper les limitations
- Gestion d'erreur gracieuse : prévoir des fallbacks en cas de 429
Structure de réponse en cas d'erreur 429
La réponse JSON contiendra toujours au minimum :
{
"error": "Too many requests"
}
Exemple d'intégration complète
class APIClient {
constructor(baseURL) {
this.baseURL = baseURL;
this.dernierAppel = 0;
this.delaiMinimum = 100; // ms entre les appels
}
async appel(endpoint) {
// Respecter un délai minimum entre appels
const maintenant = Date.now();
const tempsEcoule = maintenant - this.dernierAppel;
if (tempsEcoule < this.delaiMinimum) {
await new Promise(r => setTimeout(r, this.delaiMinimum - tempsEcoule));
}
const response = await fetch(`${this.baseURL}${endpoint}`);
this.dernierAppel = Date.now();
if (response.status === 429) {
const attenteMs = parseInt(response.headers.get('X-Rate-Limit-Retry-After-Milliseconds') || '1000');
console.warn(`Limitation activée. Attente de ${attenteMs} ms`);
await new Promise(r => setTimeout(r, attenteMs));
return this.appel(endpoint); // Retry une fois
}
const restant = response.headers.get('X-Rate-Limit-Remaining');
if (restant && parseInt(restant) < 5) {
console.info('Quota faible, ralentissement des appels');
this.delaiMinimum = 500; // Ralentir
} else {
this.delaiMinimum = 100; // Vitesse normale
}
return response.json();
}
}
Résumé
- Surveillez X-Rate-Limit-Remaining pour anticiper
- En cas de 429, attendez X-Rate-Limit-Retry-After-Milliseconds
- Implémentez une stratégie de retry intelligente
- Espacez vos requêtes pour éviter les limitations