# Errores

> Un documento de problema legible por máquina para cada fallo, y qué significa cada tipo para su lógica de reintentos.

Source: https://developers.backresto.com/es/docs/errors

Todo fallo (incluida una ruta que no existe) responde con
`application/problem+json`, la forma definida por el RFC 9457. No hay ninguna vía
en esta API que devuelva una página de error HTML, así que un parser que asuma
JSON en una respuesta no 2xx es seguro.

```json
{
  "type": "https://api.backresto.com/problems/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "The authenticated client lacks the required scope.",
  "instance": "/v1/restaurants/restaurant-1/collections/delivery-pictures/records/8f2c/assets",
  "requestId": "b1c8b0a4-6c1e-4f6b-9e1c-3b2a5d7f0e91"
}
```

`type` es el identificador estable: condicione su código a él, no a `detail`, que
es prosa y puede reformularse. `requestId` es el valor que conviene citar en un
mensaje a soporte: también se devuelve en la cabecera de respuesta
`X-Request-ID`, y usted puede establecer esa cabecera para correlacionarla con
sus propias trazas.

## El catálogo

| Sufijo de `type` | Estado | Qué ha pasado | ¿Reintentar? |
| --- | --- | --- | --- |
| `invalid-request` | 400 | Falta un parámetro o está malformado: un `limit` fuera de rango, una colección desconocida, o un cursor que no coincide con el restaurante, la colección y el `limit` con los que pagina. | No: corrija la petición. |
| `unauthorized` | 401 | Sin cabecera `Authorization`, o una clave malformada, desconocida, revocada, caducada o que se ha quedado sin ninguna concesión. | No: la clave necesita atención. |
| `forbidden` | 403 | La clave tiene una concesión para este restaurante pero no el scope que este endpoint necesita. | No: hay que pedir una clave que lleve ese scope. |
| `not-found` | 404 | Sin concesión para este restaurante, o ese registro no existe. Los casos son deliberadamente indistinguibles. | No. |
| `conflict` | 409 | La petición entra en conflicto con un recurso existente. | No. |
| `payload-too-large` | 413 | El cuerpo de la petición supera el límite. | No. |
| `rate-limit-exceeded` | 429 | Su cliente ha superado su presupuesto de peticiones. | Sí, después de `Retry-After`. |
| `dependency-unavailable` | 503 | Un componente que la API necesita no está disponible momentáneamente. | Sí, con backoff. |
| `internal-error` | 500 | Un fallo inesperado, ya registrado por nuestra parte. | Una vez, con backoff; después indíquenos el `requestId`. |

## Qué debería hacer un cliente

Tres grupos, y nada más merece la pena programar:

**No reintentar**: 400, 401, 403, 404, 409, 413. La petición volverá a fallar de
forma idéntica. Registre el `type` y el `requestId`, y hágalo visible: un `401` en
particular significa que una persona del lado de su cliente ha revocado algo, y un
bucle de reintentos solo lo ocultará durante una semana.

**Reintentar con backoff**: 429, 503. Respete `Retry-After` en un 429; es el
número de segundos hasta que se recarga su presupuesto, y no es una sugerencia.
Para un 503, backoff exponencial con jitter, y ríndase en lugar de machacar el
servicio.

**Reintentar una vez y luego escalar**: 500. Si se repite en la misma petición,
no es transitorio.

Todos los endpoints de esta API son `GET`, así que reintentar siempre es seguro
desde el punto de vista de la API; la razón para no reintentar un 4xx es que
malgasta su presupuesto, no que arriesgue una doble escritura.

## Correlacionar con sus propios logs

Envíe su propio identificador y se lo devolvemos:

```bash
curl "https://api.backresto.com/v1/restaurants/$RESTAURANT_ID/collections/deliveries/records?limit=100" \
  -H "Authorization: Bearer $BACKRESTO_PARTNER_API_KEY" \
  -H "X-Request-ID: 3f7a1c9e-2b4d-4a86-9f0c-5e1d8b6a2c40" \
  --include
```

El valor se refleja en la cabecera de respuesta y en el `requestId` de un
documento de problema, lo que hace que un solo grep responda a «¿qué vio
BackResto cuando mi tarea falló a las 04:12?».
