← APIs REST avanzadas

UD7 · Refinar

Lo que debes recordar

El método

En esta unidad has aprendido lo que distingue a una API de juguete de una API industrial: la capacidad de ser consumida por terceros de forma predecible, eficiente y sostenible en el tiempo.

Para diseñar y publicar contratos de servidor profesionales, aplica siempre este decálogo de refinamiento:

El ciclo de refinamiento de una API REST profesional
  1. Delimita la profundidad relacional: utiliza subrecursos canónicos (/padres/{id}/hijos) para colecciones numerosas y evita la recursión infinita de Jackson.
  2. Ofrece una única ruta de colección en plural y gestiona filtros y búsquedas mediante parámetros de consulta (@RequestParam).
  3. Resuelve búsquedas multicriterio con JPQL condicional con evaluación de nulos evitando explosiones de métodos en el repositorio.
  4. Blinda la memoria del servidor: ninguna colección se devuelve sin paginar; utiliza Pageable, Page<T> y @PageableDefault.
  5. Traduce la paginación a nivel de base de datos con LIMIT y OFFSET reales en PostgreSQL.
  6. Comprueba el contrato HTTP completo (rutas, estados, validaciones y cabeceras) con tests de slice web usando MockMvc.
  7. Genera documentación viva OpenAPI 3.0 a partir del código con springdoc-openapi y Swagger UI.
  8. Aplica el principio de robustez de Postel: sé tolerante con lo que recibes y riguroso con lo que envías.
  9. Versiona de forma explícita tus rutas públicas (/api/v1/...) para aislar evoluciones destructivas.
  10. Avisa de la obsolescencia con antelación utilizando las cabeceras estándar Deprecation y Sunset.

La idea más importante

Una API no se diseña para quien la programa, sino para quien la consume. La calidad de un backend se mide por la predictibilidad de sus contratos, la contención de sus respuestas y la capacidad de evolucionar sin romper a sus clientes.

Un backend descuidado devuelve árboles gigantes de datos, inventa rutas para cada filtro, agota la memoria del servidor al primer millón de registros y rompe a los clientes móviles con cada cambio de código. Una API profesional mantiene contratos estables, acota el tráfico de red y comunica con claridad cada decisión a través de estándares abiertos.

Las decisiones que tienes que saber justificar

Decisión de ingeniería Lo que tienes que poder defender ante un tribunal
Subrecursos frente a incrustación masiva La incrustación de colecciones completas satura el ancho de banda y provoca problemas de rendimiento; externalizar colecciones dinámicas a subrecursos (/proyectos/{id}/tareas) permite paginarlas y consultarlas bajo demanda.
Parámetros de consulta frente a explosión de rutas Expresar filtros mediante Query Params (/tareas?prioridad=alta) respeta la semántica de recurso único en REST y evita crear combinaciones factoriales de endpoints en el controlador.
JPQL condicional con evaluación de nulos La cláusula (:param IS NULL OR columna = :param) permite resolver filtros combinables opcionales en una única consulta limpia sin requerir librerías complejas para catálogos medianos.
Paginación obligatoria con metadatos Devolver Page<T> protege la memoria Heap de la JVM, previene colapsos del recolector de basura y proporciona al cliente los metadatos indispensables (totalElements, totalPages) para renderizar interfaces de navegación.
@PageableDefault con ordenación segura Fija límites por defecto (ej: 10 o 20 registros) para clientes que no envíen parámetros, impidiendo que peticiones maliciosas o despistadas descarguen tablas enteras.
@WebMvcTest con MockMvc Valida el protocolo HTTP real (rutas, Bean Validation, deserialización Jackson y códigos semánticos) en milisegundos sin coste de arrancar Tomcat ni conectar a bases de datos.
Documentación viva OpenAPI con springdoc Evita la desincronización entre código y documentación al generarse automáticamente de las clases compiladas, permitiendo la generación de clientes frontend sin errores manuales.
Versionado en la URI (/api/v1) Es la estrategia más explícita y compatible con la infraestructura de red (cachés HTTP, proxies inversos y balanceadores), facilitando el mantenimiento simultáneo de contratos durante transiciones.
Ley de Postel en la deserialización Ignorar propiedades desconocidas en el cuerpo JSON permite desplegar nuevas versiones de clientes sin romper a clientes antiguos que envíen campos heredados o adicionales.
Cabeceras Deprecation y Sunset Informan de forma estandarizada y automatizada a las herramientas de observabilidad de la próxima retirada de un endpoint, ofreciendo un periodo de migración predecible.

Al terminar la unidad deberías poder responder

  1. ¿Qué problemas técnicos provoca devolver directamente una entidad JPA con relaciones bidireccionales en un @RestController?
  2. ¿Qué tres patrones existen para modelar relaciones en una API REST y cuándo se aplica cada uno?
  3. ¿Por qué una petición a GET /proyectos/999/tareas debe responder con 404 Not Found y no con un array vacío []?
  4. ¿Por qué crear rutas como /tareas/urgentes o /tareas/completadas viola las buenas prácticas de diseño REST?
  5. ¿Cómo funciona la evaluación de nulos (:prioridad IS NULL OR t.prioridad = :prioridad) en una consulta JPQL?
  6. ¿Por qué una búsqueda textual con operador LIKE debe aplicar la función LOWER() a ambos lados de la comparación?
  7. ¿Qué riesgo de rendimiento asume una base de datos cuando una consulta utiliza un comodín inicial (%termino%)?
  8. ¿Qué diferencia de consumo de memoria existe entre un método que devuelve List<Tarea> y uno que devuelve Page<Tarea> sobre una tabla con 300.000 filas?
  9. ¿Cuáles son los metadatos indispensables que componen una respuesta paginada con Page<T> en Spring Boot?
  10. ¿Cómo traduce PostgreSQL la paginación de Spring Data a nivel de sintaxis SQL física?
  11. ¿En qué consiste el problema de la «paginación profunda» (Deep Paging) con OFFSET elevado y cómo lo resuelve la paginación por cursor?
  12. ¿Por qué los tests unitarios con Mockito de la capa de servicio no detectan errores de validación de Bean Validation?
  13. ¿Qué componentes del contexto de Spring se cargan al utilizar la anotación @WebMvcTest?
  14. ¿Qué expresiones JSONPath se utilizan para comprobar el estado de un campo y la longitud de un array en MockMvc?
  15. ¿Qué diferencia conceptual y práctica existe entre la especificación OpenAPI 3.0 y la herramienta Swagger UI?
  16. ¿Cómo permite un endpoint /v3/api-docs generar automáticamente un cliente TypeScript para una aplicación frontend?
  17. ¿Qué distingue a un cambio compatible (non-breaking) de un cambio incompatible (breaking) en una API pública?
  18. ¿Qué establece la Ley de Postel y por qué es un principio de resiliencia fundamental en el desarrollo web?
  19. ¿Cuáles son las tres estrategias principales para versionar una API REST y qué ventajas tiene el versionado por URI?
  20. ¿Qué propósito tienen las cabeceras HTTP estándar Deprecation y Sunset durante la retirada de un endpoint?

El vocabulario de la unidad

Concepto Significa
Payload Bloat Envío de respuestas JSON con volumen excesivo de datos innecesarios que saturan el ancho de banda y degradan la experiencia de cliente.
Subrecurso Ruta REST jerárquica (/padres/{id}/hijos) que modela la relación entre dos recursos subordinados.
Query Parameter Parámetro transmitido tras el signo ? en la URL para configurar filtros, búsquedas y paginación en colecciones canónicas.
JPQL condicional Consulta JPQL que evalúa condiciones opcionales mediante la comprobación de nulos (:param IS NULL OR ...).
Pageable Interfaz de Spring Data que encapsula la información de paginación solicitada (página, tamaño y orden).
Page<T> Contenedor de Spring que agrupa los elementos de la página actual junto con los metadatos globales de conteo y navegación.
Deep Paging Degradación severa del rendimiento en bases de datos relacionales al solicitar páginas con desplazamientos (offset) muy elevados.
Keyset Pagination Técnica de paginación por cursor basada en comparar la clave del último registro visto (WHERE id > :ultimoId LIMIT n).
MockMvc Utilidad de pruebas de Spring MVC que simula peticiones y respuestas HTTP completas sin levantar un servidor de red real.
JSONPath Lenguaje de expresiones de consulta para inspeccionar y validar atributos anidados dentro de un cuerpo JSON en tests.
OpenAPI 3.0 Estándar de especificación abierta e independiente de plataforma para describir contratos de APIs RESTful.
Swagger UI Interfaz web interactiva generada a partir de OpenAPI para explorar y ejecutar peticiones contra una API en vivo.
Breaking Change Modificación en el contrato de una API que rompe el funcionamiento de los clientes existentes no actualizados.
Ley de Postel Principio de diseño: «sé conservador con lo que envías y liberal con lo que aceptas» para maximizar la robustez del sistema.
Sunset Header Cabecera HTTP estandarizada (RFC 8594) que comunica la fecha programada para la retirada definitiva de un endpoint.

Comprobación final del producto de la unidad

Auditoría de API REST avanzada · criterios de producción

  • Los recursos relacionados se exponen mediante subrecursos desacoplados (/proyectos/{id}/tareas) con DTOs específicos que eliminan riesgos de recursión infinita.
  • Las colecciones se filtran a través de parámetros de consulta (@RequestParam) en una única ruta canónica en plural sin duplicar endpoints.
  • La búsqueda textual parcial es insensible a mayúsculas y acentos mediante LOWER() y limpia espacios en blanco.
  • Todos los endpoints de listado están protegidos por paginación obligatoria con @PageableDefault y metadatos completos (Page<T>).
  • PostgreSQL ejecuta sentencias con LIMIT, OFFSET y ORDER BY físicos, auditables en consola.
  • El contrato HTTP completo está blindado por una suite de pruebas automatizadas con @WebMvcTest y MockMvc.
  • La documentación técnica OpenAPI 3.0 se genera en /v3/api-docs y se visualiza interactivamente en /swagger-ui.html.
  • Las rutas públicas incorporan prefijo de versión (/api/v1/...) para garantizar la estabilidad de los consumidores.
  • Los endpoints u operaciones legadas emiten cabeceras estándar de obsolescencia (Deprecation y Sunset).
  • La aplicación tolera propiedades desconocidas en peticiones entrantes sin provocar errores 400 injustificados.

Resultados de la unidad

  • Exponer relaciones sin filtrar el modelo interno ni provocar respuestas gigantes.
  • Diseñar filtros y búsquedas que no se conviertan en un lenguaje de consulta improvisado.
  • Paginar y ordenar colecciones declarando siempre el total.
  • Comprobar endpoints con MockMvc sin depender de un cliente manual.
  • Documentar la API con OpenAPI y evolucionar el contrato sin romper a quien lo consume.

Ya deberías ser capaz de

  • Exponer relaciones sin filtrar el modelo interno ni provocar respuestas gigantes.
  • Diseñar filtros y búsquedas que no se conviertan en un lenguaje de consulta improvisado.
  • Paginar y ordenar colecciones declarando siempre el total.
  • Comprobar endpoints con MockMvc sin depender de un cliente manual.
  • Documentar la API con OpenAPI y evolucionar el contrato sin romper a quien lo consume.