BroadNet
HTTP API & webhooksDiseño de API

Errores de API (problem+json) y paginación (cursor, header Link)

Actualizado el 7 min de lecturaBasado en estándares
Respuesta directa

RFC 9457 problem+json estandariza las respuestas de error como un objeto JSON con type, title, status, detail e instance, servido como application/problem+json, para que los clientes parseen los errores de manera uniforme. La paginación divide las colecciones grandes en páginas usando un cursor (estable) o un offset (simple), con enlaces next/prev portados en el header Link de RFC 8288.

§01

problem+json: un objeto de error estándar

Las formas de error a medida obligan a cada cliente a tratar como caso especial cada API. RFC 9457 (que deja obsoleto RFC 7807) fija un formato de error JSON único y extensible, servido con el tipo de medio application/problem+json para que un cliente sepa parsearlo como un problema. El objeto tiene cinco miembros estándar: type, un URI que identifica la clase de problema y que hace además de enlace a documentación humana; title, un resumen breve, estable y legible por humanos de esa clase; status, el código de estado HTTP repetido en el cuerpo; detail, una explicación legible por humanos específica de esta ocurrencia; e instance, un URI que identifica esta ocurrencia concreta. Cualquier miembro adicional (un array de errores de validación, un id de petición, una pista de reintento) extiende el objeto sin romper los estándar, para que un cliente genérico lea los campos comunes y uno específico lea también las extensiones.

Cuerpo de error problem+json de RFC 9457json
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{
  "type": "https://example/problems/invalid-destination",
  "title": "Invalid destination number",
  "status": 422,
  "detail": "The field 'to' is not a valid E.164 number.",
  "instance": "/v1/messages/req-01HZY9",
  "errors": [ { "field": "to", "issue": "not_e164" } ]
}
§02

Type, title e instance

La disciplina que hace útil a problem+json es mantener type y title estables y orientados a máquina, dejando que detail e instance varíen por ocurrencia. Un cliente debería bifurcarse según type (un URI estable), nunca según la prosa de detail o title, porque detail es libre de cambiar y puede estar localizado. El URI de type idealmente resuelve a documentación de esa clase de error, para que un desarrollador que lo siga aterrice en una explicación y un remedio. instance identifica la petición fallida concreta —útil para citarla en un ticket de soporte— y a menudo refleja un id de petición que la API también devuelve en un header. Como type y title identifican la clase y status/detail/instance describen la ocurrencia, un mismo type de problema puede reutilizarse en muchos fallos sin ambigüedad.

§03

Taxonomía de errores: reintentable frente a terminal

Más allá de la forma, el cliente necesita saber qué hacer, y la clase del código de estado lo responde. Un 4xx es un error de cliente: la petición tal como se envió nunca tendrá éxito, así que reintentarla sin cambios es inútil; la solución es corregir la petición (400/422 para entrada incorrecta, 401/403 para autenticación, 404 para un recurso ausente, 409 para un conflicto). Un 5xx es un error del servidor o aguas arriba: la petición podría tener éxito más tarde, así que es reintentable con backoff, idealmente bajo el mismo Idempotency-Key para que el reintento no pueda duplicar el envío. 429 es el caso transitorio especial: reintentable, pero solo tras el retardo de Retry-After. Codificar esto en el código de estado (y reforzarlo con un type de problema) permite a un cliente decidir automáticamente entre corregir y reenviar, aplicar backoff y reintentar, o rendirse.

Clase de error y la acción correcta del cliente
ClaseSignificado¿Reintentable?Acción del cliente
400 / 422Entrada con formato incorrecto o inválidaNoCorrige la solicitud y vuelve a enviarla
401 / 403No autenticado / prohibidoNoCorregir credenciales o alcance
404Recurso no encontradoNoCorrija el identificador
409Conflicto de estado (por ejemplo, reutilización de claves)NoResolver el conflicto
429Límite de tasa excedidoSí (con retraso)Esperar Retry-After y luego reintentar
500 / 502 / 503Fallo del servidor / aguas arribaSíBackoff + reintento con la misma clave de idempotencia
§04

Paginación: cursor frente a offset

Un endpoint de colección que podría devolver millones de mensajes debe paginar. Los dos modelos principales intercambian simplicidad por corrección. La paginación por offset (?limit=50&offset=100) es trivial y permite a un cliente saltar a una página arbitraria, pero es inestable en una colección cambiante: si se insertan o borran filas entre páginas, los elementos se desplazan y el cliente salta o repite registros, y los offsets profundos se vuelven lentos porque el almacén debe escanear y descartar todo lo anterior. La paginación por cursor (keyset) entrega al cliente un cursor opaco que codifica la posición del último elemento visto (por ejemplo un id y una marca de tiempo); la siguiente petición pide filas posteriores a ese cursor. Es estable ante escrituras concurrentes y se mantiene rápida a cualquier profundidad porque la consulta busca directamente el cursor, a costa de no admitir saltos de página arbitrarios. Para recursos de alto volumen y con muchas inserciones, como los logs de mensajes, la paginación por cursor es el valor por defecto correcto.

Paginación por cursor frente a offset
PropiedadDesplazamientoCursor (conjunto de teclas)
Solicitud?limit=50&offset=100?limit=50&after=<cursor>
Salto de página arbitrarioSíNo (solo secuencial)
Estable ante inserciones/eliminacionesNo: los elementos se desplazanSí
Rendimiento en páginas profundasSe degrada (recorrido + descarte)Constante (posicionarse en el cursor)
Ideal paraColecciones pequeñas y establesRegistros grandes, principalmente de anexado
§05

El header Link (RFC 8288)

En vez de enterrar las URL de siguiente y anterior en el cuerpo, una API puede portarlas en el header Link estándar definido por RFC 8288 (Web Linking), usando tipos de relación registrados: next, prev, first, last. El cliente sigue el enlace rel="next" para avanzar sin construir URL por sí mismo ni conocer el esquema del cursor, lo que mantiene el mecanismo de paginación enteramente controlado por el servidor y le permite evolucionar (offset hoy, cursor mañana) sin romper a los clientes. Un enfoque común de cinturón y tirantes también refleja los enlaces en el cuerpo JSON para clientes que no leen headers, pero el header Link es el hogar estandarizado a nivel de transporte para ellos y es el mismo mecanismo que un navegador o un cliente de API bien educado ya entienden.

Paginación mediante el header Link de RFC 8288http
HTTP/1.1 200 OK
Content-Type: application/json
Link: </v1/messages?after=01HZY8Q3M6&limit=50>; rel="next",
      </v1/messages?limit=50>; rel="first"

{ "data": [ /* up to 50 messages */ ],
  "page": { "count": 50, "has_more": true } }
§06

Límites y valores por defecto del tamaño de página

El tamaño de página debe estar acotado en el servidor, no dejado al cliente, o una sola petición de una página enorme se convierte en un vector de denegación de servicio y una fuente de latencia impredecible. El patrón es un valor por defecto sensato (usado cuando el cliente omite limit) y un máximo estricto al que el servidor recorta en silencio: un cliente que pide más simplemente recibe el máximo. Anunciar tanto el tamaño de página efectivo como si quedan más páginas (un flag has_more o la presencia de un enlace rel="next") permite a un cliente iterar con seguridad: seguir a next hasta que no haya next. Combinado con la paginación por cursor y los errores problem+json, esto da una API de colección predecible de consumir a cualquier escala. BroadNet documenta sus códigos de error y paginación concretos para desarrolladores.

Preguntas frecuentes

Preguntas frecuentes

¿Qué es problem+json y por qué usarlo?

problem+json (RFC 9457, que deja obsoleto RFC 7807) es un formato de error JSON estándar servido como application/problem+json, con los miembros type, title, status, detail e instance. Permite a cada cliente parsear los errores de la misma forma en vez de tratar como caso especial una forma a medida por API, y es extensible para poder añadir miembros extra sin romper los estándar.

¿Sobre qué campo de problem+json debería bifurcarse un cliente?

Sobre type: un URI estable que identifica la clase de error. title y detail son legibles por humanos y pueden cambiar o estar localizados, así que el código nunca debería conmutar según su prosa. El URI de type idealmente resuelve a documentación de ese error, mientras que status, detail e instance describen la ocurrencia concreta.

¿Cómo sabe un cliente si debe reintentar un error?

Por la clase del estado. Un 4xx es un error de cliente que no tendrá éxito sin cambios, así que corrige la petición en vez de reintentar. Un 5xx es un fallo del servidor o aguas arriba que podría tener éxito más tarde, así que reintenta con backoff bajo el mismo Idempotency-Key. 429 es reintentable pero solo tras el retardo de Retry-After.

¿Cuál es la diferencia entre paginación por cursor y por offset?

El offset (?limit&offset) es simple y admite saltar a cualquier página, pero es inestable cuando se insertan o borran filas entre peticiones y se ralentiza en offsets profundos. La paginación por cursor (keyset) pasa un marcador opaco del último elemento visto y pide las filas posteriores: estable ante escrituras concurrentes y rápida a cualquier profundidad, pero solo secuencial. El cursor es el valor por defecto correcto para logs de mensajes grandes.

¿Cómo ayuda el header Link de RFC 8288 a la paginación?

Porta las URL de página next, prev, first y last en un header estándar usando tipos de relación registrados, para que el cliente siga rel="next" para avanzar sin construir URL ni conocer el esquema del cursor. Eso mantiene el mecanismo de paginación controlado por el servidor y libre de evolucionar, y es un mecanismo que los clientes HTTP genéricos ya entienden.

¿Por qué acotar el tamaño de página en el servidor?

Porque un tamaño de página sin acotar permite que una petición extraiga un conjunto de resultados enorme, lo que es un riesgo de denegación de servicio y da una latencia impredecible. El servidor aplica un valor por defecto cuando se omite limit y recorta en silencio a un máximo estricto, y anuncia si quedan más páginas para que los clientes iteren siguiendo a next hasta que no esté.

Referencias

Especificaciones de la fuente

Las normas publicadas en las que se basa esta página. Se abre en una pestaña nueva.

BNMantenido por el equipo de ingeniería BroadNet·Mensajería de nivel empresarial desde 2003.
Colócalo en el cable

Desarrollado con un enlace SMPP real y una API REST.

Solicita acceso de prueba con claves de prueba reales: primero envía a tu propio número verificado y, una vez aprobada tu identidad de remitente y las rutas, pasa a producción en más de 200 países.