Guías / Errores, idempotencia y paginación

Errores, idempotencia y paginación

Errores tipados, reintentos seguros con idempotencia, y cómo paginar.

Errores, idempotencia y paginación

Tres cosas que hacen robusta cualquier integración: entender los errores, reintentar sin duplicar, y recorrer listas grandes.

Errores tipados

Todos los errores de la API traen un cuerpo con type, code, message y un request_id (envíalo al soporte si algo falla). El SDK los mapea a clases:

import { MetRateLimitError, MetAuthError, MetInvalidRequestError } from '@meteor.ia/sdk';

try {
  await met.runs.create({ input: 'x' });
} catch (err) {
  if (err instanceof MetRateLimitError) {
    console.log(`Reintentar en ${err.retryAfter}s`);
  } else if (err instanceof MetAuthError) {
    console.log('Key inválida o revocada');
  } else if (err instanceof MetInvalidRequestError) {
    console.log(err.code, err.message);
  } else throw err;
}

La taxonomía es un conjunto cerrado:

typeClaseHTTP
authentication_errorMetAuthError401
invalid_request_errorMetInvalidRequestError400
rate_limit_errorMetRateLimitError429
agent_errorMetAgentError5xx del Met
api_errorMetApiErrorotros

Reintentos e idempotencia

El SDK reintenta solo los 429 y 5xx con backoff exponencial (respeta Retry-After). No tienes que reimplementarlo.

Para que reintentar un POST no duplique (por ejemplo, crear dos runs por un corte de red), el SDK manda una Idempotency-Key automática en cada POST con efectos. Si el request se reenvía con la misma key, la API devuelve el mismo resultado sin volver a ejecutar.

// Ambas llamadas comparten idempotencia automática; un retry no crea dos runs.
await met.runs.create({ input: 'x' });

Con curl, manda tú el header:

-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000"

Paginación

Los endpoints de lista devuelven { data, has_more } con un cursor opaco. El SDK lo recorre por ti:

for await (const run of met.runs.iterate()) {
  // ...cada run, todas las páginas
}

Si prefieres controlar el cursor a mano, list() acepta limit y starting_after:

const page = await met.runs.list({ limit: 20 });
if (page.has_more) {
  const next = await met.runs.list({ limit: 20, starting_after: page.data.at(-1).id });
}