DEV Community

ArturoAtomplay
ArturoAtomplay

Posted on

Cómo diseñar una API – guía práctica y escalable

Una API bien pensada facilita la integración, reduce errores y permite crecer sin sobresaltos.

En este artículo se recopilan los principios esenciales para crear una API clara, segura y preparada para escalar. Cada sección incluye el qué y el por qué, además de recomendaciones concretas para llevarlo a la práctica.


1. Modelo basado en recursos

Una API gira alrededor de los objetos del dominio (canales, mensajes, usuarios, archivos…). Las rutas deben describir esos recursos y nada más.

GET    /v1/channels                → lista de canales
POST   /v1/channels                → crea un canal
GET    /v1/channels/{channel_id}   → detalle de un canal
PATCH  /v1/channels/{channel_id}   → actualización parcial
DELETE /v1/channels/{channel_id}   → elimina el canal
Enter fullscreen mode Exit fullscreen mode

Este enfoque hace que la API sea intuitiva y fácil de explorar.


2. Nomenclatura consistente

  • Elige snake_case o camelCase y aplícalo en rutas, parámetros y campos JSON.
  • Evita abreviaturas ambiguas; los nombres deben describir claramente su contenido (user_idcreated_at).

La consistencia reduce la carga cognitiva y previene errores tipográficos.


3. Convenciones RESTful (o GraphQL cuando sea necesario)

  • Usa los verbos HTTP con su significado semántico (GET, POST, PUT/PATCH, DELETE).
  • Mantén los recursos como sustantivos; evita verbos en la URL (/createChannel → /channels).
  • Si la flexibilidad de consultas es crucial, ofrece una capa GraphQL paralela, pero conserva la API REST como base estable.

4. Jerarquía plana

Las URLs demasiado anidadas complican el enrutamiento y la caché.

Preferible:   /teams/{team_id}/members
En lugar de:  /teams/{team_id}/members/list
Enter fullscreen mode Exit fullscreen mode

Una estructura plana es más fácil de mantener y escalar.


5. Versionado explícito

Incluye la versión en la ruta o en un encabezado (/v1/...Accept: application/vnd.myapi.v1+json).

Define una política de deprecación: aviso mínimo 90 días, guía de migración y soporte prolongado de versiones antiguas.


6. Uso semántico de HTTP

Verbo Acción típica Idempotente
GET Obtener datos
POST Crear recursos o ejecutar acciones no idempotentes No
PUT Reemplazo completo
PATCH Actualización parcial
DELETE Eliminar recurso

Responder con códigos de estado correctos (200, 201, 204, 400, 401, 403, 404, 409, 429, 500…) completa la comunicación.


7. Formato de datos único

  • JSON como formato predeterminado.
  • Define esquemas claros mediante OpenAPI (especificación 3.x o superior).
  • Publica la especificación para que los consumidores generen SDKs automáticamente.

Herramientas como APIdog permiten diseñar, probar y documentar tu API OpenAPI de forma visual y colaborativa.


8. Validación de datos

La validación de datos es esencial para asegurar que las entradas cumplan con los requisitos esperados, previniendo errores, inyecciones y datos inconsistentes en el sistema. Define esquemas que describan la estructura, tipos y restricciones de los payloads, y aplícalos en tiempo de ejecución para transformar o rechazar datos inválidos. Alinea estos esquemas con la especificación OpenAPI para que la validación del servidor coincida exactamente con la documentación, facilitando la integración y reduciendo discrepancias.

Para implementar esto de manera eficiente, considera bibliotecas como Zod, Yup, Joi o Ajv, que ofrecen validación declarativa y soporte para TypeScript o JSON Schema.

Ejemplo de esquema:

import { z } from "zod";  // O la biblioteca elegida

const CreateChannelSchema = z.object({
  name: z.string().min(1),
  description: z.string().optional(),
  is_private: z.boolean().default(false)
});

// En el handler:
const payload = CreateChannelSchema.parse(req.body);
Enter fullscreen mode Exit fullscreen mode

Esta capa de validación robusta genera respuestas de error estructuradas automáticamente y mejora la seguridad general de la API.


9. Paginación y límites

  • Cursor‑based pagination (?limit=50&cursor=abc123).
  • Establece un máximo razonable (p.ej., 100 elementos) y permite al cliente solicitar menos.
  • Evita respuestas masivas que saturen servidores y clientes.

10. Rate limiting y back‑off

  • Cuotas definidas (p.ej., 60 req/min por token).
  • Cuando se supera, devuelve 429 Too Many Requests con encabezado Retry-After.
  • Documenta los límites por endpoint y por aplicación; los clientes deben respetar el back‑off exponencial.

11. Idempotencia cuando sea posible

  • Soporta el encabezado Idempotency-Key para POST/PUT que crean recursos.
  • Almacena la clave y la respuesta asociada durante un periodo razonable (p.ej., 24 h) para devolverla si la solicitud se repite.

12. Manejo estructurado de errores

Ejemplo de cuerpo de error:

{
   "error":{
      "code":"invalid_parameter",
      "message":"El campo 'email' es obligatorio.",
      "field":"email",
      "details":[
         {
            "code":"format_error",
            "message":"Debe ser una dirección válida"
         }
      ]
   }
}
Enter fullscreen mode Exit fullscreen mode
  • Usa códigos HTTP adecuados.
  • Un formato estructurado permite a los clientes reaccionar de forma programática (reintentos, corrección de datos, etc.).

13. Autenticación y autorización robustas

  • OAuth 2.0 con tokens de acceso y refresco.
  • Scopes granulares (channels:readmessages:write).
  • Validar siempre los permisos antes de ejecutar la acción.
  • Revocar tokens comprometidos de inmediato.

14. Webhooks y eventos

  • Ofrecer suscripciones a eventos críticos (channel_createdmessage_posteduser_updated).
  • Utilizar HTTPS y firmar los payloads (HMAC‑SHA256) para que el receptor verifique la autenticidad.
  • Definir política de reintentos (p.ej., 3 intentos con back‑off exponencial) y códigos de respuesta esperados (200 OK indica éxito).

15. Documentación viva y ejemplos

  • Mantener la especificación OpenAPI siempre sincronizada con el código.
  • Generar Swagger UI, ReDoc o Scalar para pruebas interactivas directamente desde el navegador.
  • Incluir ejemplos de request/response para los flujos más comunes (creación de canal, envío de mensaje, gestión de usuarios).

16. Pruebas de contrato y retrocompatibilidad

  • Automatizar pruebas que verifiquen que la API sigue cumpliendo su contrato (esquemas JSON, encabezados, códigos de estado).
  • Ejecutar pruebas de regresión antes de cada despliegue.
  • Adoptar semantic versioning: cambios mayores → versión mayor, adiciones compatibles → versión menor, correcciones → parche.

17. Escalabilidad horizontal

  • Stateless: cada petición lleva toda la información necesaria (token, IDs).
  • Balanceadores de carga distribuyen tráfico entre instancias idénticas.
  • Bases de datos y colas que soporten sharding/partitioning (PostgreSQL con Citus, Kafka).
  • Caché (Redis, Memcached) para lecturas frecuentes y resultados de consultas costosas.

18. Observabilidad

  • Métricas con Prometheus (cuentas de latencia, tasa de errores, QPS por endpoint).
  • Dashboards en Grafana para visualizar tendencias y detectar cuellos de botella rápidamente.
  • Logs estructurados (JSON) con contexto (request‑id, usuario, endpoint).
  • Tracing distribuido (OpenTelemetry) para seguir una solicitud a través de microservicios.
  • Alertas basadas en umbrales críticos (latencia > 500 ms, error rate > 2 %).

19. Seguridad por diseño

  • Validar y sanear todas las entradas (evitar inyección, XSS, etc.).
  • HTTPS obligatorio (TLS 1.2+).
  • Políticas CORS restrictivas (solo dominios autorizados).
  • Revisiones de seguridad periódicas y pruebas de penetración.
  • Rotación regular de credenciales y secretos.

Checklist rápido antes del lanzamiento

# Acción
1 Modelado de recursos con URLs claras y verbos HTTP correctos.
2 Nomenclatura coherente (snake_case o camelCase) en toda la API.
3 Convenciones RESTful (o GraphQL opcional) y jerarquía plana.
4 Versionado explícito y política de depreciación publicada.
5 Especificación OpenAPI actualizada y documentación interactiva (Swagger UI / ReDoc / Scalar).
6 Validación de datos con Zod (o alternativa) alineada al esquema OpenAPI.
7 Paginación basada en cursor y límites razonables.
8 Rate limiting, idempotency‑key y manejo estructurado de errores activos.
9 OAuth 2.0 con scopes granulares y validación de permisos.
10 Webhooks seguros (firma HMAC) y política de reintentos documentada.
11 Métricas con Prometheus, dashboards en Grafana y logging estructurado.
12 Pruebas de contrato y regresión en CI/CD antes de cada despliegue.
13 Arquitectura stateless, caché y colas para escalar horizontalmente.
14 Seguridad por diseño (validación, HTTPS, CORS, revisiones).

Conclusión

Aplicar estos principios produce una API que se siente natural, fiable y preparada para crecer junto con la base de usuarios. La clave está en combinar consistencia (nomenclatura, estructuras) con robustez (seguridad, observabilidad) y flexibilidad (versionado, paginación, idempotencia).

Comentarios, experiencias propias son bienvenidas!

Happy Coding! 💻

Top comments (0)