02 / Cómo funciona Lupus
CE API y JSON:API
JSON:API responde a “qué datos tiene este recurso”. CE API responde a “qué presentación compatible entrega Drupal para esta ruta”. La diferencia es dónde se decide la composición, no que una API sea universalmente mejor.
Todos los recorridos ↗Con JSON:API
Se consultan recursos por tipo y UUID, con atributos, relaciones, filtros, includes y paginación de recursos. El frontend decide consultas, composición y vistas. Es útil para aplicaciones, múltiples canales y datos no ligados a una página. No ejecuta por defecto el display de nuestra View ni define un sistema visual.
Con /ce-api
Se pide /ce-api/demo/insights?page=1. Drupal resuelve la ruta, comprueba acceso, ejecuta la View y entrega elementos de teaser y pager. Next.js no vuelve a formular los filtros de publicación o idioma de esa View; presenta el contrato recibido.
Menos lógica duplicada, no cero frontend
El frontend sigue implementando cada componente, navegación, enlaces de paginación, estados de error y accesibilidad. CE no envía el código React ni convierte bibliotecas Drupal en React. Un elemento nuevo requiere un renderer o componente compatible.
No es una API de escritura universal
La API de página no sustituye operaciones CRUD, búsquedas especializadas o servicios de negocio. Se puede combinar CE para páginas y JSON:API u otras APIs para datos e interacciones. Esta POC no habilita JSON:API: el ejemplo de su URL es ilustrativo, no un endpoint ejecutado aquí.
Ejemplo real de esta instalación
Respuesta real de la segunda página de la View: rows contiene teasers; props.pager conserva totalPages y current. El ejemplo JSON:API de contraste sería GET /jsonapi/node/ntt_insight/{uuid}.
Inspeccionar contrato recibido en servidor
{
"title": "Ideas que conectan tecnologia y experiencia",
"content_format": "json",
"content": {
"element": "ntt-insights",
"props": {
"title": "Ideas que conectan tecnologia y experiencia",
"viewId": "ntt_demo_insights",
"displayId": "page_1",
"rowsWrapper": "",
"pager": {
"totalPages": 2,
"current": 1
}
},
"slots": {
"rows": [
{
"element": "ntt-insight-card",
"props": {
"href": "/demo/insights/production-readiness",
"title": "Formularios e integraciones: responsabilidades claras"
},
"slots": {
"body": "Drupal puede conservar Form API, validación y procesamiento; el frontal necesita integrar el ciclo completo."
}
}
]
}
},
"metatags": {
"meta": [],
"link": []
},
"blocks": {
"sidebar_first": {
"canvas_lupus_theme_page_title": {
"element": "drupal-markup",
"slots": {
"default": "\n\n"
}
},
"canvas_lupus_theme_powered": {
"element": "drupal-markup",
"slots": {
"default": "<span>Powered by <a href=\"https://www.drupal.org\">Drupal</a></span>"
}
}
},
"header": {
"canvas_lupus_theme_site_branding": {
"element": "drupal-markup",
"slots": {
"default": "<img src=\"https://dev-headless-lupus.pantheonsite.io/themes/custom/canvas_lupus_theme/logo.svg\" alt=\"Home\" />\nCanvas Lupus POC"
}
}
},
"primary_menu": {
"canvas_lupus_theme_main_menu": {
"element": "drupal-markup",
"slots": {
"default": "\n <ul>\n <li>\n <a href=\"/\" data-drupal-link-system-path=\"<front>\">Home</a>\n </li>\n </ul>\n \n\n"
}
}
},
"secondary_menu": {
"canvas_lupus_theme_account_menu": {
"element": "drupal-markup",
"slots": {
"default": "\n <ul>\n <li>\n <a href=\"/user/login\" data-drupal-link-system-path=\"user/login\">Log in</a>\n </li>\n </ul>\n \n\n"
}
}
},
"highlighted": {
"canvas_lupus_theme_messages": {
"element": "drupal-markup",
"slots": {
"default": "<div data-drupal-messages-fallback class=\"hidden\"></div>"
}
}
},
"breadcrumb": {
"canvas_lupus_theme_breadcrumbs": {
"element": "drupal-markup",
"slots": {
"default": " <nav aria-labelledby=\"system-breadcrumb\">\n <h2 id=\"system-breadcrumb\" class=\"visually-hidden\">Breadcrumb</h2>\n <ol>\n <li>\n <a href=\"/\">Home</a>\n </li>\n </ol>\n </nav>\n"
}
}
}
}
}