L'endpoint di reset password implementa rate limiting per prevenire abusi:
429 Too Many Requests con codice RATE_LIMIT_ERROR quando il limite viene superato{
"status": "error",
"error": {
"code": "RATE_LIMIT_ERROR",
"message": "Troppi tentativi di reset password. Riprova più tardi.",
"details": {}
}
}
I limiti di rate previsti variano in base al tipo di autenticazione:
| Tipo Autenticazione | Limite Pianificato | Finestra |
|---|---|---|
| PASETO Token (utenti) | 100 richieste/minuto | Per utente |
| API Key | 1000 richieste/minuto | Per chiave |
Quando implementato, ogni risposta includerà header informativi sui limiti:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642248000
Retry-After: 60
Quando implementato, superando il limite riceverai una risposta 429 Too Many Requests:
{
"status": "error",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Troppe richieste. Riprova più tardi.",
"details": {
"retryAfter": 60,
"limit": 100,
"remaining": 0,
"resetAt": "2024-01-15T10:31:00.000Z"
}
},
"meta": {
"requestId": "uuid-unico",
"timestamp": "2024-01-15T10:30:00.000Z"
}
}
Anche se il rate limiting generale non è ancora implementato, è consigliabile seguire queste best practices per prepararsi all'implementazione futura e per essere buoni cittadini dell'API:
Quando ricevi un errore 429 (attualmente solo per reset password), implementa un backoff esponenziale:
async function makeRequestWithRetry(url: string, options: RequestInit, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
const data = await response.json();
const retryAfter = data.error?.details?.retryAfter || Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Retrying after ${retryAfter}ms`);
await sleep(retryAfter);
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
await sleep(Math.pow(2, attempt) * 1000);
}
}
}
Quando il rate limiting sarà implementato, controlla sempre gli header per sapere quanti request ti rimangono:
const response = await fetch(url, options);
const remaining = parseInt(response.headers.get("X-RateLimit-Remaining") || "0");
if (remaining < 10) {
// Riduci la frequenza delle richieste
await sleep(1000);
}
Riduci le richieste usando cache per dati che cambiano raramente:
const cache = new Map();
async function getCachedData(key: string, ttl: number, fetcher: () => Promise<any>) {
const cached = cache.get(key);
if (cached && Date.now() - cached.timestamp < ttl) {
return cached.data;
}
const data = await fetcher();
cache.set(key, { data, timestamp: Date.now() });
return data;
}
Invece di fare molte richieste singole, usa endpoint batch quando disponibili:
// ❌ Male: molte richieste
for (const id of ids) {
await fetch(`/api/v1/organizations/${id}`);
}
// ✅ Meglio: una richiesta batch
await fetch("/api/v1/organizations/batch", {
method: "POST",
body: JSON.stringify({ ids }),
});
Per applicazioni che fanno molte richieste, implementa una coda:
class RequestQueue {
private queue: Array<() => Promise<any>> = [];
private processing = false;
private rateLimit = 100; // richieste per minuto
private interval = 60000; // 1 minuto
async add(request: () => Promise<any>) {
return new Promise((resolve, reject) => {
this.queue.push(async () => {
try {
const result = await request();
resolve(result);
} catch (error) {
reject(error);
}
});
this.process();
});
}
private async process() {
if (this.processing) return;
this.processing = true;
const startTime = Date.now();
let requestCount = 0;
while (this.queue.length > 0) {
if (requestCount >= this.rateLimit) {
const elapsed = Date.now() - startTime;
const waitTime = Math.max(0, this.interval - elapsed);
await sleep(waitTime);
requestCount = 0;
}
const request = this.queue.shift();
if (request) {
await request();
requestCount++;
}
}
this.processing = false;
}
}
Anche se il rate limiting generale non è ancora implementato, è buona pratica monitorare le tue richieste:
class RateLimitMonitor {
private requests: number[] = [];
recordRequest() {
const now = Date.now();
this.requests.push(now);
// Rimuovi richieste più vecchie di 1 minuto
this.requests = this.requests.filter((time) => now - time < 60000);
}
getRemainingRequests(limit: number): number {
return Math.max(0, limit - this.requests.length);
}
getTimeUntilReset(): number {
if (this.requests.length === 0) return 0;
const oldest = Math.min(...this.requests);
return Math.max(0, 60000 - (Date.now() - oldest));
}
}