Errores
La forma
Todo fallo devuelve application/problem+json, siguiendo la
RFC 9457. El estado HTTP te dice
la clase de problema; code te dice exactamente cuál.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
X-Request-Id: req_4b81f0c9
{
"type": "https://skautik.com/docs/developers/errors#validation_failed",
"title": "Validation failed",
"status": 422,
"code": "validation_failed",
"detail": "One or more fields could not be accepted.",
"request_id": "req_4b81f0c9",
"errors": [
{
"field": "price",
"code": "out_of_range",
"detail": "Must be a positive integer in minor units."
},
{
"field": "address.country",
"code": "unknown_value",
"detail": "Expected an ISO 3166-1 alpha-2 code."
}
]
}El array errors solo aparece en un 422. Nombra todos los problemas de una vez y no
solo el primero, así que un formulario se puede corregir de una pasada en lugar de un campo por
viaje de ida y vuelta.
Ramifica según code y no según la prosa de title o detail. El código es
estable; la prosa está escrita para una persona y puede reescribirse.
Códigos
| Código | Estado | Significado | Qué hacer |
|---|---|---|---|
authentication_required | 401 | Sin clave, o con una clave no válida. | Arregla la cabecera o la clave. Reintentar sin cambios no funcionará nunca. |
permission_denied | 403 | Clave válida, pero el permiso o la propiedad de la ficha lo prohíben. | Usa una clave con permiso de escritura, o deja de intentar modificar una ficha que no publicaste. |
not_found | 404 | No existe ese recurso, o ninguno que tu clave pueda ver. | Trátalo como ausencia. No es un fallo pasajero. |
conflict | 409 | Se reutilizó una Idempotency-Key con un cuerpo distinto. | Genera una clave nueva para una creación genuinamente nueva. |
managed_by_import | 409 | La ficha pertenece a una fuente de importación, que es la autoridad sobre ella. | Cámbiala en el sistema que alimenta la importación, no aquí. |
precondition_failed | 412 | El If-Match no coincidió con el ETag actual. | Vuelve a leer, aplica de nuevo tu cambio, reintenta una vez. |
payload_too_large | 413 | La subida supera el límite de su endpoint. | Redimensiona antes de subir. No reintentes los mismos bytes. |
unsupported_media_type | 415 | Falta el Content-Type o no se acepta. | Envía application/json, o multipart/form-data para subidas. |
validation_failed | 422 | El cuerpo se analizó pero un campo es inaceptable. | Lee el array errors; cada entrada nombra un campo y por qué falló. |
rate_limited | 429 | Límite de ráfaga superado. El volumen mensual no rechaza. | Espera el Retry-After y reintenta con un margen aleatorio. |
internal_error | 500 | Un fallo por nuestro lado. | Reintenta con espera exponencial. Cita el request_id si persiste. |
service_unavailable | 503 | Temporalmente incapaz de servir, normalmente durante un despliegue. | Reintenta con espera. Suele resolverse en segundos. |
Qué reintentar
La regla es sencilla, y equivocarse con ella es la forma más habitual de que una integración convierta una caída pequeña en una grande.
- 4xx: no reintentes, salvo que sea un 429. La petición está mal, y repetirla seguirá estando mal. Las excepciones son el 429 y el 412, que se reintenta una vez tras volver a leer.
- 5xx: reintenta con espera exponencial y margen aleatorio, hasta un presupuesto acotado. Nunca en un bucle cerrado: un servicio que está sufriendo se recupera más despacio cuanto más lo empujas.
- Las expiraciones son ambiguas. Una petición que expiró puede haberse aplicado igualmente. Justo para eso están las claves de idempotencia en las escrituras.
Informar de un problema
Cita el request_id cuando escribas a
support@skautik.com. Con él podemos encontrar la petición
exacta; sin él, lo primero que pediremos es una reproducción. Registra la
cabecera en cada llamada fallida para tenerla cuando la necesites.