Errores y códigos de estado

Max PrilutskiyCEO y cofundador8 min de lectura

La llamada funciona en desarrollo. Ahora toca escribir la parte que se ejecuta en producción: el bloque catch. Por sí solo, un error HTTP de una API de terceros no aclara mucho: un código de estado en rojo y ninguna respuesta evidente a la única pregunta que importa a las tres de la mañana: ¿el problema está en mi solicitud, mi clave, mi plan o sus servidores? Y, de estos errores, ¿cuáles debo reintentar y cuáles debo mostrar al usuario?

Lingo.dev responde con una estructura clara. Todos los errores de los endpoints de estas páginas, tanto síncronos como asíncronos, devuelven el mismo objeto JSON con un código de estado tomado de una tabla fija. La API de plataforma en /v2 utiliza, en cambio, el formato estándar de detalles de problemas; consulta Errores de la API de plataforma. El código de estado no es una etiqueta, sino una instrucción: te indica si debes corregir la solicitud, rotar la clave, recargar la cuenta, esperar o reintentar. Lee el código y sabrás cuál es el siguiente paso. Un único gestor de errores, basado en el código de estado, cubre toda la API.

En esta página

Formato de los errores#

Todas las respuestas fuera del rango 2xx tienen el mismo cuerpo: un objeto JSON con un único campo message que describe qué ha fallado.

json
{
  "message": "Invalid API key"
}

Ese es todo el contrato. No hay ninguna estructura envolvente que desempaquetar ni formatos de error específicos de cada endpoint que debas tratar por separado. Un 400 de /process/localize y un 404 al consultar un trabajo devuelven el mismo formato: solo cambian el código de estado y el texto de message.

Basa la lógica en el código de estado, no en el texto del mensaje

El código de estado HTTP es la señal estable: úsalo para decidir cómo gestionar el error. La cadena message está pensada para quien lee un registro; trátala como una descripción, no como un código de error interpretable por una máquina, y no bases la lógica en coincidencias con su redacción exacta.

Códigos de estado#

Siete códigos de estado cubren todas las respuestas. Aquí se agrupan según quién debe resolverlos, porque esa agrupación también determina tu política de reintentos.

Has enviado algo que impide atender la solicitud (corrígela, no reintentes a ciegas):

EstadoSignificado
400 Bad RequestLa solicitud no ha superado la validación: falta un campo, hay un idioma no válido, un callbackUrl con HTTP (no HTTPS) o un cuerpo de solicitud mal formado.
401 UnauthorizedFalta la cabecera X-API-Key o no es válida. Consulta Autenticación.
403 ForbiddenLa clave es válida, pero no tiene acceso al recurso solicitado.
404 Not FoundEl recurso —un motor, un trabajo o un grupo de trabajos— no existe.

Tu organización ha alcanzado un límite de la cuenta (resuélvelo en facturación):

EstadoSignificado
402 Payment RequiredLa organización ha alcanzado su límite de crédito.
429 Too Many RequestsLa organización ha alcanzado su cuota diaria de tokens. Cambia a un plan superior para aumentar el límite.

Algo ha fallado por nuestra parte (es transitorio: reintenta):

EstadoSignificado
500 Internal Server ErrorUn fallo inesperado: un error en la base de datos o una llamada de traducción que ha fallado en todos los modelos configurados en el motor.

Un 401 y un 403 se parecen, pero no indican el mismo problema: 401 significa que no hemos podido identificar quién hace la llamada; 403 significa que hemos identificado la clave, pero no tiene permitido el acceso. Para resolver un 401, debes actuar sobre la propia clave (rótala o compruébala); para resolver un 403, sobre sus permisos de acceso.

Qué errores reintentar#

Al integrar una API, la primera pregunta que se plantea con espíritu crítico ante una tabla de errores suele ser justo la que queda sin respuesta: ¿cuáles de estos errores debo reintentar? La agrupación anterior te da la respuesta.

  • 4xx: no reintentes a ciegas. Un 400, 401, 403 o 404 describe una condición de tu solicitud. Repetir la misma solicitud reproduce el mismo error. Corrige los datos de entrada, la clave o el ID del recurso y vuelve a enviarla.
  • 402 y 429: espera y después resuelve el límite. No son errores transitorios a nivel de solicitud: la siguiente solicitud seguirá chocando con el mismo límite hasta que este cambie. Deja de reintentar en un bucle sin pausas, muestra el límite y resuélvelo (recarga la cuenta o cambia a un plan superior).
  • 500: reintenta con esperas progresivas. Esta es la única clase de error realmente transitoria. Un 500 puede significar que todos los modelos configurados han agotado el tiempo de espera en esa llamada; un reintento puede llegar a un modelo que funcione correctamente. Usa esperas exponenciales y fija un máximo de reintentos.

La API asíncrona informa de los resultados de otra forma

Esta política de reintentos se aplica a las llamadas síncronas que haces directamente. La API de localización asíncrona no te devuelve un código de estado con el resultado del trabajo: un POST devuelve 202 una vez aceptada la solicitud, y cada idioma de destino se procesa como un trabajo independiente mediante flujos de trabajo duraderos en segundo plano. Para obtener el resultado, consultas periódicamente el trabajo o recibes un webhook, en lugar de capturar un código de estado en la llamada original. Consulta dónde se registran los errores de trabajos asíncronos.

402 frente a 429: dos límites distintos#

Los dos códigos relativos a la cuenta se parecen: ambos suenan a «has agotado algo», y confundirlos lleva a aplicar la solución equivocada durante el desarrollo. Son límites distintos con soluciones distintas:

  • 402 Payment Required: la organización ha alcanzado su límite de crédito. Es un límite de facturación. La siguiente llamada seguirá fallando hasta que cambie el estado de facturación de tu organización.
  • 429 Too Many Requests: la organización ha alcanzado su cuota diaria de tokens. Es un límite de uso que se restablece y que puedes aumentar cambiando a un plan superior.

Por eso conviene tratarlos por separado en tu gestor de errores: un 402 exige que una persona actúe sobre la facturación; ante un 429, puedes esperar a que se restablezca la cuota o aumentarla cambiando a un plan superior. Mostrar un mensaje genérico de «problema de pago» para ambos oculta qué debe hacer realmente quien gestiona la cuenta.

El cuerpo de un 402 tiene el mismo formato que el de cualquier otro error: es el código de estado lo que indica que se trata de un límite de crédito:

json
{
  "message": "Organization has reached its credit limit"
}

Dónde se registran los errores de trabajos asíncronos#

Conviene hacer una distinción, porque marca el punto en el que un gestor basado en códigos de estado deja de ser la herramienta adecuada.

Los códigos de estado de esta página son de la capa de transporte: describen si la API ha aceptado y ha podido atender tu solicitud HTTP. Un 202 de la API asíncrona significa que se ha aceptado tu solicitud, no que la traducción se haya completado correctamente. Un trabajo asíncrono puede aceptarse sin problemas y aun así fallar después, cuando un modelo agota el tiempo de espera durante la ejecución. Ese fallo no aparece como un código de estado HTTP en tu llamada original: se registra en el propio trabajo.

Por tanto, los fallos asíncronos aparecen en tres lugares, ninguno de ellos en esta tabla:

  • Estado de cada trabajo. Si falla un idioma, su trabajo incluye status: "failed" y un errorMessage. Consulta estados de los trabajos.
  • Estado del grupo. Cuando algunos idiomas se completan correctamente y otros fallan, el grupo indica partial; los idiomas completados correctamente se entregan igualmente. Consulta seguimiento de un grupo de trabajos.
  • Entrega de webhooks. El fallo se notifica mediante un evento translation.failed con un campo error. Consulta entrega de webhooks.

Hay otra distinción que suele causar confusión: que falle una etapa no crítica del flujo de procesamiento no hace que falle el trabajo. El trabajo se completa con completed_with_warnings y advertencias por paso en lugar de un error. Es una cuestión de observabilidad del flujo de procesamiento, no un código de error; consulta observar las ejecuciones del flujo de procesamiento.

Errores de la API de plataforma#

La API de plataforma en https://api.lingo.dev/v2 devuelve los errores de otra forma. Utiliza el formato de detalles de problemas de RFC 9457, enviado como application/problem+json:

json
{
  "type": "https://lingo.dev/docs/api/errors/glossary-in-use",
  "status": 409,
  "title": "Glossary in use",
  "detail": "Glossary gls_1 cannot be deleted while 2 engines apply it. Detach it from those engines first.",
  "id": "gls_1",
  "engineCount": 2
}
  • type identifica el problema. Es un enlace a la página específica de ese problema, que enumera sus campos y los endpoints que lo devuelven. Usa type para decidir cómo gestionarlo.
  • status repite el código de estado HTTP.
  • title es un resumen breve, idéntico cada vez que se produce un problema del mismo tipo.
  • detail indica qué ha ocurrido esta vez y qué hacer a continuación. Está pensado para una persona, así que muéstralo en lugar de analizar su contenido mediante código.
  • Otros miembros contienen los datos de este caso concreto, como id y engineCount en el ejemplo anterior. detail se construye únicamente a partir de ellos, por lo que un cliente puede generar su propio texto, en su propio idioma, a partir de type y estos campos.

Una solicitud que no supera la validación devuelve 400 y enumera cada valor no válido en errors, como pares { "path", "message" }. Todos los endpoints también pueden devolver service-unavailable (503), ante el que es seguro reintentar con esperas progresivas, e internal-server-error (500).

Cada código de estado sigue una regla:

EstadoSignificado
401No se ha identificado a quien hace la llamada.
402Un límite del plan o de los derechos de acceso que se elimina al cambiar a un plan superior o recargar la cuenta.
403Se ha identificado a quien hace la llamada, pero no tiene permitido realizar esta acción.
404El recurso no existe o quien hace la llamada no puede verlo.
409La solicitud entra en conflicto con el estado actual; por ejemplo, con un recurso que todavía está en uso.
422La solicitud está bien formada, pero una regla la rechaza.
429Un límite que se restablece con el tiempo.
502Ha fallado un proveedor del que depende el servicio.
503Un fallo temporal por nuestra parte. Reintenta con esperas progresivas.

Siguientes pasos#

Un gestor de errores bien diseñado empieza por las dos cuestiones que te encontrarás primero durante la integración: la autenticación y los puntos en los que el trabajo asíncrono informa de su propio resultado.