CiberForja

Diseña una API REST robusta y segura

Aprende a diseñar APIs REST profesionales: convenciones de URL, versionado, autenticación, control de errores, documentación y buenas prácticas de seguridad.

CCiberForja·1 de junio de 2026·15 min de lectura
Compartir:

Una API REST bien diseñada es la columna vertebral de cualquier aplicación moderna. Ya sea que estés construyendo una aplicación móvil, un frontend de página única (SPA), una integración B2B con terceros o una arquitectura de microservicios, la calidad del contrato que define tu API determina la facilidad con la que otros sistemas (y futuros tú) pueden integrarse y evolucionar. Una API con un diseño descuidado se convierte rápidamente en deuda técnica que ralentiza a todo el equipo.

REST (Representational State Transfer) no es un protocolo estricto sino un conjunto de restricciones arquitectónicas propuestas por Roy Fielding en su tesis doctoral del año 2000. En la práctica, la mayoría de las APIs llamadas REST son en realidad APIs HTTP con recursos, verbos y códigos de estado HTTP semánticos, lo que en ocasiones se denomina nivel 2 del modelo de madurez de Richardson. Alcanzar ese nivel de forma consistente y segura ya es suficiente para la mayoría de los casos de uso empresariales.

Esta guía cubre todos los aspectos que necesitas considerar al diseñar y construir una API REST profesional: desde las convenciones de nomenclatura de URLs hasta la autenticación, el manejo de errores, el versionado, la limitación de tráfico y la documentación. Los ejemplos están orientados a Node.js con Express o Fastify, pero los principios son agnósticos al lenguaje.

Diseño de recursos y URLs: las convenciones que importan

La URL es el nombre de un recurso, no de una acción. Este principio fundamental distingue un diseño REST de un diseño RPC disfrazado de REST. En lugar de /getUser?id=123 o /createOrder, usamos /users/123 (con GET para obtener, PUT/PATCH para actualizar, DELETE para eliminar) y /orders (con POST para crear). Los recursos se nombran en plural y en minúsculas, con guiones para separar palabras si fuera necesario: /product-categories es mejor que /productCategories o /ProductCategories.

Las relaciones entre recursos se expresan anidando rutas, pero con moderación. /users/123/orders es perfectamente válido para obtener los pedidos de un usuario específico. Sin embargo, /users/123/orders/456/items/789/reviews empieza a ser excesivamente profundo y difícil de mantener. Como regla práctica, limita el anidamiento a dos o tres niveles como máximo; para recursos más profundos, considera usar parámetros de consulta o endpoints planos con filtros.

Uso correcto de los verbos HTTP

  • GET: obtener un recurso o colección. Debe ser idempotente y seguro (sin efectos secundarios). Nunca usar para acciones que modifican datos.
  • POST: crear un nuevo recurso en una colección. Devuelve 201 Created con la cabecera Location apuntando al nuevo recurso.
  • PUT: reemplazar completamente un recurso existente. El cliente debe enviar toda la representación del recurso.
  • PATCH: actualizar parcialmente un recurso. El cliente envía solo los campos que quiere modificar.
  • DELETE: eliminar un recurso. Devuelve 204 No Content si tiene éxito o 404 si el recurso no existe.
  • OPTIONS: obtener los métodos HTTP permitidos para un recurso. Fundamental para el preflight de CORS.

Códigos de estado HTTP: habla el idioma del protocolo

Los códigos de estado HTTP comunican el resultado de una operación de forma estándar que todos los clientes entienden. Usarlos correctamente permite que proxies, caches, herramientas de monitorización y clientes manejen las respuestas de forma automática e inteligente. Un error muy común es devolver siempre 200 OK con un campo error en el cuerpo: esto rompe todas las capas de la infraestructura HTTP que entienden los códigos de estado.

  • 200 OK: solicitud exitosa con contenido en el cuerpo.
  • 201 Created: recurso creado exitosamente. Incluir cabecera Location con la URL del nuevo recurso.
  • 204 No Content: operación exitosa sin contenido que devolver (típico en DELETE y algunos PUT).
  • 400 Bad Request: el cliente envió datos inválidos. Incluir detalles del error en el cuerpo.
  • 401 Unauthorized: falta autenticación o token inválido.
  • 403 Forbidden: autenticado pero sin permiso para la operación.
  • 404 Not Found: el recurso solicitado no existe.
  • 409 Conflict: conflicto con el estado actual del recurso (p.ej., email ya registrado).
  • 422 Unprocessable Entity: los datos están bien formados pero contienen errores semánticos.
  • 429 Too Many Requests: el cliente ha superado el límite de tasa.
  • 500 Internal Server Error: error no anticipado en el servidor. No filtrar detalles internos al cliente.

Diseño de respuestas: consistencia ante todo

Las respuestas de tu API deben seguir un esquema consistente en toda la superficie de la API. Una inconsistencia muy común es que algunos endpoints devuelvan directamente el objeto de datos y otros lo envuelvan en un objeto con metadatos. Elige una convención y aplícala uniformemente. Una estructura popular y práctica es envolver siempre las respuestas exitosas con un campo data y las de error con un campo error que contenga code, message y opcionalmente details.

Para colecciones, incluye siempre información de paginación junto a los datos: el total de resultados, la página actual, el número de resultados por página y, si es posible, links a la página anterior y siguiente (paginación basada en cursores es superior a la paginación por offset para datasets grandes que cambian con frecuencia). Los clientes deben poder saber si han recibido todos los resultados o hay más páginas disponibles sin tener que hacer inferencias a partir del tamaño del array recibido.

Filtrado, ordenación y búsqueda

El filtrado de colecciones se implementa con parámetros de consulta descriptivos: /products?category=electronics&inStock=true&minPrice=100. La ordenación con un parámetro sort que acepte el nombre del campo y opcionalmente un prefijo - para orden descendente: /products?sort=-createdAt,name. La búsqueda de texto libre con un parámetro q o search. Define claramente en la documentación qué campos son filtrables y cuáles son ordenables, y asegúrate de que tienen los índices de base de datos correspondientes para no crear consultas lentas sin querer.

Autenticación y autorización en APIs REST

La autenticación verifica quién es el cliente; la autorización determina qué puede hacer. Son conceptos distintos que a menudo se confunden. Para APIs REST, el mecanismo de autenticación más extendido es JWT (JSON Web Tokens) en combinación con OAuth 2.0 para escenarios de delegación de autorización. Una API interna usada solo por tu propio frontend puede simplificar el proceso usando JWT directamente sin OAuth completo, pero las APIs expuestas a terceros deben implementar el flujo OAuth 2.0 completo.

Los JWT tienen ventajas claras para APIs stateless: el servidor no necesita mantener estado de sesión, son escalables horizontalmente sin necesidad de sesiones compartidas, y el payload puede contener información del usuario y sus permisos sin una consulta adicional a la base de datos. Sus desventajas son la dificultad de invalidación antes de la expiración y el riesgo de incluir demasiada información sensible en el payload. Usa tiempos de expiración cortos (15-60 minutos) para los access tokens y refresh tokens con revocación en base de datos para mitigar el primer problema.

API Keys para integraciones máquina a máquina

Para integraciones B2B donde un sistema backend se comunica con tu API sin intervención humana, las API Keys son más sencillas que OAuth 2.0. Genera claves largas, aleatorias (al menos 32 bytes de entropía) y guárdalas hasheadas en la base de datos (como contraseñas, nunca en claro). Permite al usuario regenerar sus claves en caso de compromiso. Considera implementar scopes en las API Keys: una clave con permiso solo lectura, otra con permisos de escritura, otra con acceso a los webhooks. Esta granularidad reduce el radio de impacto si una clave se ve comprometida.

Seguridad: las amenazas más comunes y cómo mitigarlas

La seguridad de una API no es un añadido posterior; debe estar integrada en el diseño desde el principio. Las vulnerabilidades más comunes en APIs REST están catalogadas en el OWASP API Security Top 10, una referencia imprescindible para cualquier equipo que construya APIs. Las tres amenazas más frecuentes en APIs de producción son: autorización a nivel de objeto rota (BOLA/IDOR), donde un usuario puede acceder a recursos de otros usuarios; autorización a nivel de función rota, donde un usuario accede a funciones que no debería; y exposición excesiva de datos, donde la API devuelve más campos de los necesarios.

  • Validar siempre los datos de entrada en el servidor, sin confiar en la validación del cliente. Usa librerías como Zod, Joi o express-validator.
  • Implementar rate limiting por usuario y por IP para prevenir ataques de fuerza bruta y abuso. libreries como express-rate-limit o servicios como Cloudflare.
  • Usar HTTPS en todos los entornos, incluyendo desarrollo y staging. Let's Encrypt hace gratuito el certificado TLS.
  • Configurar las cabeceras de seguridad HTTP: CORS restrictivo, HSTS, X-Content-Type-Options, X-Frame-Options. Helmet.js automatiza esto en Express.
  • No exponer IDs secuenciales en las URLs: usa UUIDs o IDs opacos para evitar enumeración de recursos.
  • Implementar Object-Level Authorization en cada endpoint: verifica que el usuario autenticado tiene acceso al recurso específico que solicita, no solo que está autenticado.
  • Registrar todas las operaciones sensibles (login, cambio de contraseña, acceso a datos de pago) en logs inmutables con timestamps.

Versionado de APIs: estrategias y buenas prácticas

Versionar tu API desde el principio te da la libertad de evolucionar el contrato sin romper a los clientes existentes. La estrategia más extendida es incluir la versión en la URL: /api/v1/users, /api/v2/users. Es explícita, fácil de enrutar en proxies y gateways, y deja claro en los logs y métricas qué versión está usando cada cliente. Alternativas como la versión en headers (Accept: application/vnd.myapi.v1+json) son más puras desde el punto de vista REST pero más complejas de implementar y consumir.

Una política de deprecación clara es tan importante como el versionado en sí. Cuando publicas una nueva versión, anuncia la fecha de fin de soporte de la versión anterior con suficiente antelación (mínimo 6 meses para APIs públicas, 3 meses para APIs internas). Añade la cabecera Deprecation en las respuestas de la versión antigua indicando la fecha de sunset. Monitoriza qué clientes siguen usando la versión deprecada para contactarles proactivamente si se acerca la fecha límite y no han migrado.

Rate Limiting y cuotas de uso

El rate limiting protege tu API de abusos, ataques de denegación de servicio y clientes con bugs que generan bucles infinitos de peticiones. La granularidad adecuada depende del caso de uso: rate limiting por IP para proteger endpoints públicos como el login, rate limiting por API Key o usuario para APIs autenticadas, y rate limiting global para proteger la infraestructura. Una configuración típica podría ser 100 peticiones por minuto por usuario para endpoints de lectura y 20 peticiones por minuto para endpoints de escritura.

Cuando el cliente supera el límite, devuelve 429 Too Many Requests con las cabeceras estándar que le informan de cuándo puede reintentar: Retry-After con el número de segundos a esperar, X-RateLimit-Limit con el límite total, X-RateLimit-Remaining con las peticiones restantes y X-RateLimit-Reset con el timestamp Unix del momento en que se reseteará el contador. Un cliente bien implementado usará esta información para implementar backoff automático sin molestar al usuario.

Manejo de errores: mensajes útiles sin revelar internos

Los errores son parte del contrato de tu API y deben diseñarse con el mismo cuidado que los casos de éxito. Un buen mensaje de error ayuda al desarrollador a entender qué salió mal y cómo corregirlo sin necesidad de leer el código fuente de tu API. Incluye siempre: un código de error legible por máquina (p.ej., VALIDATION_ERROR, USER_NOT_FOUND, INSUFFICIENT_PERMISSIONS), un mensaje legible por humanos en el idioma del cliente si soportas i18n, y cuando sea apropiado, detalles sobre qué campo específico tiene el problema.

Lo que no debes incluir en los mensajes de error de producción es información interna: stack traces, queries SQL, nombres de tablas, rutas del sistema de ficheros del servidor o versiones de dependencias. Esta información es un regalo para un atacante que está probando tu API en busca de vulnerabilidades. Registra esa información internamente en tus logs para el equipo de desarrollo, pero devuelve al cliente solo lo que necesita saber para resolver su problema.

Documentación con OpenAPI (Swagger)

OpenAPI (anteriormente conocido como Swagger) es el estándar de la industria para documentar APIs REST. Defines tu API en un fichero YAML o JSON que describe cada endpoint, sus parámetros, los esquemas de request y response y los mecanismos de autenticación. A partir de esa especificación, herramientas como Swagger UI o ReDoc generan documentación interactiva que permite a los desarrolladores explorar y probar la API directamente desde el navegador, sin necesidad de configurar Postman ni escribir código de prueba.

El enfoque code-first, donde generas la especificación OpenAPI automáticamente desde tu código usando decoradores o comentarios JSDoc, reduce el riesgo de que la documentación quede desactualizada respecto a la implementación real. Librerías como fastify-swagger, tsoa para TypeScript o springdoc para Spring Boot hacen este proceso casi automático. El enfoque design-first, donde escribes la especificación antes de implementar, tiene la ventaja de permitir contratos explícitos y generar código de stubs para cliente y servidor, pero requiere más disciplina de equipo.

Testing de APIs: estrategia multicapa

Una API sin tests es una API que no puedes evolucionar con confianza. La estrategia de testing para APIs tiene varias capas complementarias. Los tests de integración —los más importantes para APIs— verifican que un endpoint completo (routing, validación, lógica de negocio, base de datos) funciona correctamente. Herramientas como Supertest para Node.js permiten hacer peticiones HTTP reales contra tu servidor en un entorno de test controlado con una base de datos de prueba.

Los tests de contrato con herramientas como Pact garantizan que el contrato entre proveedor y consumidor de la API no se rompe cuando uno de los dos evoluciona. Son especialmente valiosos en arquitecturas de microservicios donde un cambio en un servicio puede romper silenciosamente a varios consumidores. Los tests de carga con k6 o Artillery verifican que la API mantiene los SLAs de rendimiento bajo carga sostenida y picos de tráfico, y son imprescindibles antes de cualquier lanzamiento importante.

Monitorización y observabilidad de la API

En producción, necesitas visibilidad sobre cómo se está usando tu API y si está funcionando correctamente. Las métricas fundamentales son las llamadas cuatro señales doradas: latencia (cuánto tardan las peticiones), tasa de tráfico (peticiones por segundo), tasa de error (porcentaje de peticiones que devuelven 5xx o 4xx inesperados) y saturación (uso de recursos: CPU, memoria, conexiones de base de datos). Herramientas como Prometheus + Grafana, Datadog o New Relic facilitan la recopilación y visualización de estas métricas.

El tracing distribuido es especialmente valioso en arquitecturas con múltiples servicios. Herramientas como Jaeger u OpenTelemetry permiten seguir el rastro de una petición a través de todos los servicios que toca, identificar dónde se introduce latencia y qué dependencia está fallando cuando el usuario experimenta un error. La correlación de IDs en los logs (un ID único por petición propagado a través de todos los servicios) es el mínimo imprescindible si aún no tienes tracing completo.

Una API es un producto. Sus consumidores son tus clientes. Diseñarla con el mismo cuidado que diseñarías una interfaz de usuario —clara, consistente, con buen manejo de errores y documentada— es la diferencia entre una API que se adopta y una que se evita.

¿Te ha servido? Compártelo

Compartir:
C
Escrito por
CiberForja

Consultor TI. Especializado en sistemas, redes y ciberseguridad.

Más sobre nosotros →

Comentarios

Sé el primero en comentar.

Deja tu comentario

Sigue leyendo