Errores y Límites de Tasa
Maneja errores de API y límites de tasa usando las clases de error tipadas y la lógica de reintentos integrada de WhataloClient.
WhataloClient lanza clases de error tipadas para cada respuesta que no sea 2xx. Capturar tipos de error específicos te permite manejar fallos con precisión y mostrar mensajes significativos a los comerciantes.
Jerarquía de Clases de Error
Todos los errores extienden WhataloAPIError, que proporciona los campos comunes compartidos entre todos los tipos de error.
import {
WhataloAPIError,
AuthenticationError,
AuthorizationError,
NotFoundError,
ValidationError,
RateLimitError,
InternalError,
} from "@whatalo/plugin-sdk";Campos Comunes (WhataloAPIError)
| Campo | Tipo | Descripción |
|---|---|---|
statusCode | number | Código de estado HTTP de la respuesta |
code | string | Código de error legible por máquina |
requestId | string | undefined | ID único de solicitud para escalación de soporte |
message | string | Descripción legible por humanos |
Referencia de Clases de Error
| Clase | Estado HTTP | Código | Campos extra |
|---|---|---|---|
AuthenticationError | 401 | authentication_error | — |
AuthorizationError | 403 | authorization_error | requiredScope: string |
NotFoundError | 404 | not_found | resourceType: string, resourceId: string |
ValidationError | 422 | validation_error | fieldErrors: { field, message }[] |
RateLimitError | 429 | rate_limit_exceeded | retryAfter: number (segundos) |
InternalError | 500 | internal_error | — |
Ejemplos de Manejo de Errores
Patrón básico
import {
WhataloClient,
NotFoundError,
RateLimitError,
ValidationError,
AuthorizationError,
AuthenticationError,
} from "@whatalo/plugin-sdk";
const client = new WhataloClient({ apiKey: process.env.WHATALO_API_KEY! });
try {
const product = await client.products.get("999999999999");
} catch (error) {
if (error instanceof NotFoundError) {
// Product does not exist
console.log(`${error.resourceType} not found: ${error.resourceId}`);
} else if (error instanceof AuthorizationError) {
// Plugin is missing the required scope
console.log(`Insufficient permissions. Required: ${error.requiredScope}`);
} else if (error instanceof AuthenticationError) {
// API key is invalid or has been revoked
console.log("Invalid API key — check your WHATALO_API_KEY");
} else if (error instanceof RateLimitError) {
// Too many requests — wait before retrying
console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
} else if (error instanceof ValidationError) {
// Request body failed validation
error.fieldErrors.forEach((e) => {
console.log(` ${e.field}: ${e.message}`);
});
} else {
// Unknown error — re-throw so it surfaces properly
throw error;
}
}Manejo de errores de validación en create/update
import { ValidationError } from "@whatalo/plugin-sdk";
try {
await client.products.create({
name: "", // Empty name is invalid
price: -5, // Negative price is invalid
});
} catch (error) {
if (error instanceof ValidationError) {
const messages = error.fieldErrors
.map((e) => `${e.field}: ${e.message}`)
.join("\n");
throw new Error(`Product creation failed:\n${messages}`);
}
throw error;
}Límites de Tasa
Leer el estado del límite de tasa
Después de cada llamada a la API, el cliente actualiza su propiedad rateLimit leyendo los encabezados de la respuesta:
await client.products.list({ page: 1, per_page: 10 });
console.log(client.rateLimit);
// { limit: 100, remaining: 89, reset: 1709280000 }| Campo | Encabezado fuente | Descripción |
|---|---|---|
limit | X-RateLimit-Limit | Máximo de solicitudes por ventana |
remaining | X-RateLimit-Remaining | Solicitudes restantes en la ventana actual |
reset | X-RateLimit-Reset | Marca de tiempo Unix cuando se restablece la ventana |
Verificaciones proactivas de límite de tasa
Para operaciones por lotes, verifica client.rateLimit.remaining antes de cada llamada:
const productIds = ["472819365001", "472819365002", "472819365003", /* ... */];
for (const id of productIds) {
// Pause if fewer than 10 requests remain to avoid hitting the limit
if (client.rateLimit.remaining < 10) {
const msUntilReset = client.rateLimit.reset * 1000 - Date.now();
await new Promise((resolve) => setTimeout(resolve, msUntilReset + 100));
}
await client.products.get(id);
}Reintentos Automáticos
Configura retries en el cliente para reintentar automáticamente errores 5xx con backoff exponencial:
const client = new WhataloClient({
apiKey: process.env.WHATALO_API_KEY!,
retries: 3, // Retry up to 3 times on server errors
});| Intento | Retraso |
|---|---|
| 1er reintento | 1 segundo |
| 2do reintento | 2 segundos |
| 3er reintento | 4 segundos |
RateLimitError (429) no se reintenta automáticamente. Usa error.retryAfter para programar tu propio reintento:
import { RateLimitError } from "@whatalo/plugin-sdk";
async function withRateLimitRetry<T>(fn: () => Promise<T>): Promise<T> {
try {
return await fn();
} catch (error) {
if (error instanceof RateLimitError) {
await new Promise((resolve) =>
setTimeout(resolve, error.retryAfter * 1000)
);
return fn(); // Single retry after the window resets
}
throw error;
}
}
const product = await withRateLimitRetry(() =>
client.products.get("472819365047")
);Registro de IDs de Solicitud
Incluye requestId en los logs de error para facilitar la escalación de soporte:
import { WhataloAPIError } from "@whatalo/plugin-sdk";
try {
await client.orders.get("order_123");
} catch (error) {
if (error instanceof WhataloAPIError) {
console.error({
message: error.message,
code: error.code,
statusCode: error.statusCode,
requestId: error.requestId, // Include in support tickets
});
}
throw error;
}