Procesamiento de errores y códigos de estado
1) Por qué estandarizar errores
El contrato de error único acelera la depuración de los clientes, reduce los falsos retratos y hace reproducible el RCA. Buen sistema:- codifica previsiblemente el tipo de problema,
- da al cliente pistas válidas (qué hacer a continuación),
- protege contra la fuga de piezas internas,
- compatible con retraídas e idempotencia.
2) Principios de diseño
1. Un esquema de errores para todos los servicios (NAT/GraphQL/gRPC/webhooks).
2. Una clara semántica de retraídas: qué códigos retraer, cuáles no.
3. Fail-closed en las operaciones de escritura: mejor 4xx/5xx que la inconsistencia silenciosa.
4. Sin fugas: no revelar SQL, pilas, confecciones, ID interno.
5. Rastreo: siempre devuelve 'trace _ id '/' correlation _ id'.
6. Localización de mensajes - opcional, pero los códigos y 'reason' se mantienen estables.
3) Formato único (Detalles del problema/JSON)
Formato básico recomendado (compatible con RFC 7807):json
{
"type": "https://errors.example.com/auth/invalid-token",
"title": "Invalid access token",
"status": 401,
"code": "AUTH_INVALID_TOKEN",
"detail": "Token expired or signature invalid.",
"instance": "/api/v1/payments/12345",
"trace_id": "01HX3...ABC",
"hint": "Obtain a new token via OAuth2 refresh.",
"meta": {
"scope": "payments:write",
"policy": "deny-by-default"
}
}
Explicaciones:
- 'type' es un identificador de URL estable de clase de error.
- 'code' es un código de máquina corto de un dominio (estable entre lanzamientos).
- 'hint' - qué hacer al cliente (repetir, actualizar el token, cambiar los parámetros).
- 'meta' - detalles seguros (sin secretos y PII).
4) Mapa de códigos de estado (conjunto mínimo)
Autenticación/autorización
400 Bad Request - validación estructural/esquema.
401 Unauthorized - No/No es un token invisible. Agregue 'WWW-Authenticate'.
403 Forbidden - autenticado, pero no se han denegado derechos/políticas.
404 Not Found - Enmascara la existencia de un recurso si no hay derechos.
409 Conflict es un conflicto de versiones/estados (bloqueo optimístico, idempotencia).
451 Unavailable For Legal Reasons - Bloque de cumplimiento/jurisdicción.
Límites y protección
408 Request Timeout: el cliente envía el cuerpo demasiado lentamente.
409/425 Too Early - Prohibición de repetición temprana en el 0-RTT/TLS 1. 3.
429 Too Many Requests - con 'Retry-After' y política de límites.
499 Client Closed Request - (en el perímetro/NGINX) el cliente rompió la conexión.
Datos y reglas de negocio
422 Contenido no procesable: la validación empresarial ha pasado el esquema, pero el significado es incorrecto.
423 Bloqueado: el recurso está bloqueado (revisión KYC, AML freeze).
409 Conflict - Doble envío, carrera, límite de estado (por ejemplo, «ya en proceso»).
410 Gone - Endpoint/recurso eliminado (deprechate completado).
Del servidor
500 Error de servidor interno: error desconocido; no revelar detalles.
502 Bad Gateway: la dependencia devolvió el error/proxy.
503 Service Unavailable - degradación/trabajo planificado; añadir 'Retry-After'.
504 Gateway Timeout - Timaut de dependencias.
5) Semántica de retraídas e idempotencia
No se puede retractar: 400/ 401/403/404/422 (a menos que el cliente haya modificado la solicitud).
Se puede retractar: 408/429/5xx/ 425/499/504 (con backoff + jitter).
Idempotencia: para 'POST', incluye 'Idempotency-Key' (UUIDv4).
En el conflicto de repetición, devuelva 409 con 'hint: "Use same Idempotency-Key or GET status" ".
Añade 'Idempotency-Replay: true' cuando devuelvas el resultado guardado.
HTTP/1.1 429 Too Many Requests
Retry-After: 3
RateLimit-Limit: 50
RateLimit-Remaining: 0
RateLimit-Reset: 1730641030
6) Validación de entrada: estructura de errores de campo
Para 400/422, utilice la matriz de errores de campo:json
{
"type": "https://errors.example.com/validation",
"title": "Validation failed",
"status": 422,
"code": "VALIDATION_ERROR",
"trace_id": "01HX4...XYZ",
"errors": [
{"field": "amount", "rule": "min", "message": "Must be >= 10"},
{"field": "currency", "rule": "enum", "message": "Unsupported currency"}
]
}
7) Fallas parciales (batch/falla parcial)
En los endpoints de batch, no esconda errores dentro de 200 sin estructura. Devuelva 207 Multi-Status o 200 con la matriz de resultados donde cada trabajo tiene su estado:json
{
"status": "partial",
"succeeded": 8,
"failed": 2,
"results": [
{"id": "op1", "status": 201},
{"id": "op2", "status": 422, "error": {"code":"VALIDATION_ERROR","detail":"..."}}
]
}
8) Paginación y respuestas «vacías»
Colección vacía - 200 s 'items: []', no 404.
El final de la página es 'next _ page _ token'.
Token incorrecto - 400 s 'code: PAGINATION_CURSOR_INVALID'.
9) Webhooks: entrega confiable
Firme eventos (HMAC) y compruebe antes del procesamiento.
La respuesta a un procesamiento exitoso es 2xx (mejor que 204).
Fallas temporales del destinatario - 5xx; el remitente repite (backoff exponencial, jitter).
Deduplicar por 'event _ id' y guardar el resultado (consumidor idempotent).
Payload no válido - 400/422 sin repeticiones.
10) Cumplimiento de protocolos (gRPC/GraphQL)
gRPC → HTTP:- `INVALID_ARGUMENT` → 400
- `UNAUTHENTICATED` → 401
- `PERMISSION_DENIED` → 403
- `NOT_FOUND` → 404
- `ALREADY_EXISTS` → 409
- `FAILED_PRECONDITION` → 412/422
- `RESOURCE_EXHAUSTED` → 429
- `ABORTED` → 409
- `UNAVAILABLE` → 503
- `DEADLINE_EXCEEDED` → 504
json
{
"data": { "createPayment": null },
"errors": [{
"message": "Forbidden",
"extensions": { "code": "FORBIDDEN", "status": 403, "trace_id": "..." },
"path": ["createPayment"]
}]
}
Se recomienda no utilizar 200 para errores críticos, sino el código HTTP correspondiente.
11) Encabezados y consejos al cliente
'Retry-After' - segundos/NTTR-fecha (429/503/425/408).
'Warning' es una degradación suave o deprechate («199 - Feature X is deprecated»).
`Deprecation`, `Sunset`, `Link: <...>; rel = "deprecation" "- para desconexión controlada.
'Problem-Type' (personalizado) - Enrutamiento rápido de errores en el cliente.
'X-Trace-Id '/' Correlation-Id' - enlaza logs/tracks.
12) Seguridad de mensajes
No repita los secretos de entrada (tokens/firmas) en el cuerpo de respuesta.
Enmascarar PAN/PII ('1234').
Para 401/403 - no revele exactamente qué atributo falló.
Para 404, en lugar de «resource exists but not yours» - simplemente 404.
13) Observabilidad de errores
Métricas:- `http_errors_total{status, route, tenant}`
- 'error _ classes _ total {code}' (por 'código' del cuerpo)
- share 429, 5xx; 'p95 '/' p99' latency para respuestas erróneas por separado
- 'retry _ after _ seconds _ bucket' - un histograma de consejos de repetición
- asocie la respuesta a 'trace _ id', almacene 'code', 'type', 'status', 'route', 'tenant', sin PII.
- el estallido '5xx _ rate> X%' en RPS> N;
- crecimiento de 429 en rutas críticas;
- 'timeout/504' en dependencias;
- 409/idempotencia frecuentes → signo de carreras.
14) Ejemplos
14. 1.422 (validación de negocios)
json
{
"type": "https://errors.example.com/payments/limit-exceeded",
"title": "Limit exceeded",
"status": 422,
"code": "PAYMENT_LIMIT_EXCEEDED",
"detail": "Daily withdrawal limit reached for KYC1.",
"hint": "Increase limits after KYC2 or try tomorrow.",
"trace_id": "01J5...XYZ"
}
14. 2.409 (idempotencia)
HTTP/1.1 409 Conflict
Idempotency-Replay: true
json
{
"type": "https://errors.example.com/idempotency/replay",
"title": "Duplicate request",
"status": 409,
"code": "IDEMPOTENT_REPLAY",
"detail": "A request with the same Idempotency-Key was already processed.",
"hint": "Reuse the same Idempotency-Key and GET the operation status."
}
14. 3.429 (límites)
json
{
"type":"https://errors.example.com/rate/too-many-requests",
"title":"Too many requests",
"status":429,
"code":"RATE_LIMITED",
"detail":"Per-key rate limit exceeded.",
"hint":"Retry after the time specified in Retry-After header."
}
15) Antipattern
Devolver 200 con texto de error en el cuerpo.
Mezclar diferentes formatos de error entre servicios.
Revelar pila/SQL/nombres de tabla/URL internas en 'detail'.
Utilice 'message' en lugar de 'code '/' type' estable.
Devuelve 500 en un error de negocio esperado (por ejemplo, «el balance es insuficiente»).
Semántica inconsistente entre NAT/GraphQL/gRPC.
16) Especificidad de iGaming/finanzas
Códigos claros para KYC/AML/sanciones: 'KYC _ REQUIRED', 'KYC _ REVIEW', 'AML _ LOCK', 'SANCTION _ BLOCKED'.
Restricciones jurisdiccionales: 451 con una formulación segura sin especificar listas.
Operaciones de escritura en efectivo: 409/423 cuando se compite y se bloquea, 'hint' con ventana de repetición.
Invariantes de límite de jugador: use 422 para violar las reglas de pago responsable.
Auditoría: registros de soluciones inmutables (código, tiempo, actor, trace_id).
17) Lista de comprobación de disponibilidad
- Circuito único de errores JSON, estable 'type '/' code'.
- El mapping HTTP ↔ gRPC/GraphQL está negociado y documentado.
- Semántica Retraye + 'Retry-After'; idempotencia para escribir.
- Enmascarar PII/secretos; 404 para ocultar recursos.
- Métricas de errores y alertas; Corelación con 'trace _ id'.
- Políticos de deprechate: 'Deprecation', 'Sunset', 'Link'.
- Pruebas: negative/fuzz, conflicto de versiones, caída de dependencias, doble-submit.
- Hyde a los clientes: ejemplos de back-offs y procesamiento 409/422/429/5xx.
18) TL; DR
Estandarizar un formato de error JSON único c 'type '/' code '/' trace _ id', utilizar códigos HTTP correctos, distinguir validación (400/422), derechos de (401/403/404), conflictos/idempotencia (409) y límites (429). Seamos claros 'Retry-After' e 'hint', enmascara datos sensibles, lógica errores con 'trace _ id' y construya alertas de 5xx/429/p99.