alltools.one
API
2025-06-30
9 min
alltools.one Team
JSONAPIRESTDesign PatternsBackend

Patrones de Diseño de JSON API: Construyendo Mejores REST APIs

Una API bien diseñada es un placer de usar. Una mal diseñada crea errores, frustración y deuda técnica. Esta guía cubre patrones probados en batalla para diseñar JSON REST APIs que sean consistentes, descubribles y mantenibles.

Nomenclatura de Recursos

Los recursos son sustantivos, no verbos. Usa sustantivos en plural para colecciones y recursos individuales mediante ID:

GET    /api/users          # List users
POST   /api/users          # Create a user
GET    /api/users/123      # Get user 123
PUT    /api/users/123      # Update user 123
DELETE /api/users/123      # Delete user 123

Convenciones de nomenclatura:

  • Usa minúsculas con guiones: /api/blog-posts (no blogPosts ni blog_posts)
  • Anida recursos relacionados: /api/users/123/orders
  • Limita la anidación a 2 niveles: /api/users/123/orders/456 (no más profundo)
  • Evita verbos en URLs: /api/users/123/activate es aceptable para acciones que no se mapean a CRUD

Envoltorio de Respuesta

Envuelve las respuestas en un envoltorio consistente:

{
  "data": {
    "id": "123",
    "type": "user",
    "attributes": {
      "name": "Alice",
      "email": "alice@example.com",
      "createdAt": "2024-01-15T10:30:00Z"
    }
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

Para colecciones:

{
  "data": [
    { "id": "123", "name": "Alice" },
    { "id": "456", "name": "Bob" }
  ],
  "meta": {
    "total": 142,
    "page": 1,
    "perPage": 20
  }
}

Valida las respuestas de tu API con nuestro Validador JSON para asegurar que coincidan con tu esquema.

Paginación

Tres enfoques comunes:

Basada en Offset (La Más Simple)

GET /api/users?page=2&per_page=20
{
  "data": [...],
  "meta": {
    "page": 2,
    "perPage": 20,
    "total": 142,
    "totalPages": 8
  }
}

Ventaja: Simple, permite saltar a cualquier página. Desventaja: Resultados inconsistentes con inserciones/eliminaciones concurrentes.

Basada en Cursor (La Más Confiable)

GET /api/users?cursor=eyJpZCI6MTIzfQ&limit=20
{
  "data": [...],
  "meta": {
    "hasNext": true,
    "nextCursor": "eyJpZCI6MTQzfQ"
  }
}

Ventaja: Consistente con cambios concurrentes, eficiente en conjuntos de datos grandes. Desventaja: No se puede saltar a páginas arbitrarias.

Basada en Keyset (La Más Eficiente)

GET /api/users?after_id=123&limit=20

Usa el ID del último elemento (u otro campo ordenado) para obtener la siguiente página. Similar a la basada en cursor pero con parámetros transparentes.

Recomendación: Usa basada en cursor para feeds en tiempo real y conjuntos de datos grandes. Usa basada en offset para paneles de administración donde importa saltar entre páginas.

Filtrado y Ordenamiento

Filtrado

GET /api/users?status=active&role=admin
GET /api/users?created_after=2024-01-01
GET /api/users?search=alice

Para filtros complejos, considera un parámetro de consulta dedicado:

GET /api/users?filter[status]=active&filter[role]=admin

Ordenamiento

GET /api/users?sort=name          # Ascendente
GET /api/users?sort=-created_at   # Descendente (prefijo con -)
GET /api/users?sort=-created_at,name  # Múltiples campos

Manejo de Errores

Las respuestas de error consistentes son críticas para la usabilidad de la API:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address",
        "value": "not-an-email"
      },
      {
        "field": "age",
        "message": "Must be between 0 and 150",
        "value": -5
      }
    ]
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

Códigos de estado HTTP a usar:

CódigoSignificadoCuándo
200OKGET, PUT exitoso
201CreadoPOST exitoso
204Sin ContenidoDELETE exitoso
400Solicitud IncorrectaErrores de validación
401No AutorizadoAutenticación faltante/inválida
403ProhibidoAutenticación válida, permisos insuficientes
404No EncontradoEl recurso no existe
409ConflictoRecurso duplicado, conflicto de versión
422No ProcesableSemánticamente inválido
429Demasiadas SolicitudesLímite de tasa excedido
500Error InternoError inesperado del servidor

Versionado

Tres enfoques:

Ruta en URL (Recomendado)

GET /api/v1/users
GET /api/v2/users

Ventaja: Explícito, fácil de enrutar, fácil de probar.

Basado en Header

GET /api/users
Accept: application/vnd.myapi.v2+json

Ventaja: URLs limpias. Desventaja: Más difícil de probar, menos descubrible.

Parámetro de Consulta

GET /api/users?version=2

Ventaja: Fácil de probar. Desventaja: Semántica de parámetro opcional.

Recomendación: El versionado por ruta en URL es la opción más práctica. Es explícito, cacheable y funciona con todas las herramientas HTTP.

Manejo de Fechas y Horas

Siempre usa ISO 8601 en UTC:

{
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T14:22:33Z",
  "expiresAt": "2024-12-31T23:59:59Z"
}

Nunca uses timestamps Unix en respuestas de API — son ambiguos (segundos vs milisegundos) y no son legibles por humanos. Para más sobre manejo de timestamps, consulta nuestra guía de Timestamps Unix.

Limitación de Tasa

Comunica los límites de tasa en los headers de respuesta:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 67
X-RateLimit-Reset: 1705312800
Retry-After: 30

Devuelve 429 Too Many Requests cuando se exceda el límite, con un mensaje de error claro y el header Retry-After.

HATEOAS (Opcional pero Poderoso)

Incluye enlaces a recursos y acciones relacionadas:

{
  "data": {
    "id": "123",
    "name": "Alice",
    "links": {
      "self": "/api/users/123",
      "orders": "/api/users/123/orders",
      "avatar": "/api/users/123/avatar"
    }
  }
}

Esto hace que tu API sea auto-documentada y reduce la construcción de URLs del lado del cliente.

FAQ

¿Debería usar la especificación JSON:API o diseñar mi propio formato?

La especificación JSON:API (jsonapi.org) proporciona un estándar integral, pero puede ser verboso para APIs simples. Para la mayoría de los proyectos, diseñar un formato personalizado más simple siguiendo los patrones de esta guía es más práctico. Usa JSON:API si necesitas bibliotecas de cliente automáticas y un estándar estricto.

¿Cómo debo manejar actualizaciones parciales (PATCH vs PUT)?

Usa PUT para reemplazo completo de recursos (el cliente envía todos los campos). Usa PATCH para actualizaciones parciales (el cliente envía solo los campos modificados). PATCH con JSON Merge Patch (RFC 7396) es el enfoque más simple: envía un objeto JSON con solo los campos a actualizar, y null para eliminar un campo.

Recursos Relacionados

Published on 2025-06-30
JSON API Design Patterns: Building Better REST APIs | alltools.one