Saltearse al contenido

Drupal & Astro

Drupal es una herramienta de gestión de contenido de código abierto.

Para comenzar, necesitarás tener lo siguiente:

  1. Un proyecto Astro - Si aún no tienes un proyecto Astro, nuestra guía de instalación te pondrá en marcha en poco tiempo.

  2. Un sitio Drupal - Si no has configurado un sitio Drupal, puedes seguir las directrices oficiales Instalación de Drupal.

Instalación del módulo JSON:API de Drupal

Sección titulada Instalación del módulo JSON:API de Drupal

Para poder obtener contenido de Drupal, necesitas habilitar el módulo JSON:API de Drupal.

  1. Navega a la página Extender admin/modules a través del menú administrativo Administrar.
  2. Localiza el módulo JSON:API y marca la casilla junto a él.
  3. Haz clic en Instalar para instalar el nuevo módulo.

Ahora puedes hacer solicitudes GET a tu aplicación Drupal a través de JSON:API.

Para agregar tu URL de Drupal a Astro, crea un archivo .env en la raíz de tu proyecto (si aún no existe) y agrega la siguiente variable:

.env
DRUPAL_BASE_URL="[https://drupal.ddev.site/](https://drupal.ddev.site/)"

Reinicia el servidor de desarrollo para usar esta variable de entorno en tu proyecto Astro.

De forma predeterminada, el punto de conexión JSON:API de Drupal es accesible para solicitudes de obtención de datos externas sin requerir autenticación. Esto te permite obtener datos para tu proyecto Astro sin credenciales, pero no permite a los usuarios modificar tus datos o la configuración del sitio.

Sin embargo, si deseas restringir el acceso y requerir autenticación, Drupal proporciona varios métodos de autenticación que incluyen:

Puedes agregar tus credenciales a tu archivo .env.

.env
DRUPAL_BASIC_USERNAME="editor"
DRUPAL_BASIC_PASSWORD="editor"
DRUPAL_JWT_TOKEN="abc123"
...
Lee más sobre el uso de variables de entorno y archivos .env en Astro.

Tu directorio raíz ahora debería incluir estos nuevos archivos:

  • .env
  • astro.config.mjs
  • package.json

Las solicitudes y respuestas JSON:API a menudo pueden ser complejas y estar profundamente anidadas. Para simplificar el trabajo con ellas, puedes usar dos paquetes npm que agilizan tanto las solicitudes como el manejo de respuestas:

  • JSONA: Serializador y deserializador de la especificación JSON API v1.0 para usar en el servidor y en el navegador.
  • Drupal JSON-API Params: Este módulo proporciona una clase auxiliar para crear la consulta requerida. Al hacerlo, también intenta optimizar la consulta utilizando la forma abreviada, siempre que sea posible.
Ventana de terminal
npm install jsona drupal-jsonapi-params

Tu contenido se obtiene de una URL JSON:API.

Estructura de la URL JSON:API de Drupal

Sección titulada Estructura de la URL JSON:API de Drupal

La estructura básica de la URL es: /jsonapi/{entity_type_id}/{bundle_id}

La URL siempre está prefijada por jsonapi.

  • El entity_type_id se refiere al Tipo de entidad, como nodo, bloque, usuario, etc.
  • El bundle_id se refiere a los Paquetes de entidad. En el caso de un tipo de entidad Nodo, el paquete podría ser artículo.
  • En este caso, para obtener la lista de todos los artículos, la URL será [DRUPAL_BASE_URL]/jsonapi/node/article.

Para recuperar una entidad individual, la estructura de la URL será /jsonapi/{entity_type_id}/{bundle_id}/{uuid}, donde uuid es el UUID de la entidad. Por ejemplo, la URL para obtener un artículo específico será de la forma /jsonapi/node/article/2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e.

Recuperación de ciertos campos solamente

Sección titulada Recuperación de ciertos campos solamente

Recupera ciertos campos solamente agregando el campo Cadena de consulta a la solicitud.

GET: /jsonapi/{entity_type_id}/{bundle_id}?field[entity_type]=field_list

Ejemplos:

  • /jsonapi/node/article?fields[node--article]=title,created
  • /jsonapi/node/article/2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e?fields[node--article]=title,created,body

Agrega un filtro a tu solicitud agregando la Cadena de consulta de filtro.

El filtro más simple y común es un filtro de clave-valor:

GET: /jsonapi/{entity_type_id}/{bundle_id}?filter[field_name]=value&filter[field_other]=value

Ejemplos:

  • /jsonapi/node/article?filter[title]=Testing JSON:API&filter[status]=1
  • /jsonapi/node/article/2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e?fields[node--article]=title&filter[title]=Testing JSON:API

Puedes encontrar más opciones de consulta en la Documentación de JSON:API.

Construcción de una consulta de Drupal

Sección titulada Construcción de una consulta de Drupal

Los componentes Astro pueden obtener datos de tu sitio Drupal utilizando el paquete drupal-jsonapi-params para construir la consulta.

El siguiente ejemplo muestra un componente con una consulta para un tipo de contenido “artículo” que tiene un campo de texto para un título y un campo de texto enriquecido para el contenido:

---
import { Jsona } from "jsona";
import { DrupalJsonApiParams } from "drupal-jsonapi-params";
import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
// Obtener la URL base de Drupal
export const baseUrl: string = import.meta.env.DRUPAL_BASE_URL;
// Generar la consulta JSON:API. Obtener todos los títulos y cuerpos de los artículos publicados.
const params: DrupalJsonApiParams = new DrupalJsonApiParams();
params.addFields("node--article", ["title", "body"]).addFilter("status", "1");
// Genera la cadena de consulta.
const path: string = params.getQueryString();
const url: string = baseUrl + "/jsonapi/node/article?" + path;
// Obtener los artículos
const request: Response = await fetch(url);
const json: string | TJsonApiBody = await request.json();
// Iniciar Jsona.
const dataFormatter: Jsona = new Jsona();
// Deserializar la respuesta.
const articles = dataFormatter.deserialize(json);
---
<body>
{
articles?.length ? (
articles.map((article: any) => (
<section>
<h2>{article.title}</h2>
<article set:html={article.body.value} />
</section>
))
) : (
<div>
<h1>No se encontró contenido</h1>
</div>
)
}
</body>

Puedes encontrar más opciones de consulta en la Documentación de JSON:API de Drupal

Creación de un blog con Astro y Drupal

Sección titulada Creación de un blog con Astro y Drupal

Con la configuración anterior, ahora puedes crear un blog que use Drupal como CMS.

  1. Un proyecto Astro con JSONA y Drupal JSON-API Params instalados.

  2. Un sitio Drupal con al menos una entrada - Para este tutorial, recomendamos comenzar con un nuevo sitio Drupal con instalación estándar.

    En la sección Contenido de tu sitio Drupal, crea una nueva entrada haciendo clic en el botón Agregar. Luego, elige Artículo y completa los campos:

    • Título: ¡Mi primer artículo para Astro!
    • Alias: /articles/first-article-for astro
    • Descripción: ¡Este es mi primer artículo de Astro! ¡Veamos cómo se verá!

    Haz clic en Guardar para crear tu primer Artículo. Siéntete libre de agregar tantos artículos como desees.

Visualización de una lista de artículos

Sección titulada Visualización de una lista de artículos
  1. Crea src/types.ts si aún no existe y agrega dos nuevas interfaces llamadas DrupalNode y Path con el siguiente código. Estas interfaces coincidirán con los campos de tu tipo de contenido de artículo en Drupal y los campos Path. Las usarás para tipar tu respuesta de entradas de artículo.

    src/types.ts
    export interface Path {
    alias: string;
    pid: number;
    langcode: string;
    }
    export interface DrupalNode extends Record<string, any> {
    id: string;
    type: string;
    langcode: string;
    status: boolean;
    drupal_internal__nid: number;
    drupal_internal__vid: number;
    changed: string;
    created: string;
    title: string;
    default_langcode: boolean;
    sticky: boolean;
    path: Path;
    }

    Tu directorio src ahora debería incluir el nuevo archivo:

    • .env
    • astro.config.mjs
    • package.json
    • Directorysrc/
      • types.ts
  2. Crea un nuevo archivo llamado drupal.ts en src/api y agrega el siguiente código:

    src/api/drupal.ts
    import { Jsona } from "jsona";
    import { DrupalJsonApiParams } from "drupal-jsonapi-params";
    import type { DrupalNode } from "../types.ts";
    import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
    // Obtener la URL base de Drupal.
    export const baseUrl: string = import.meta.env.DRUPAL_BASE_URL;

    Esto importará las bibliotecas requeridas, como Jsona para deserializar la respuesta, DrupalJsonApiParams para formatear la URL de la solicitud y los tipos Node y Jsona. También obtendrá el baseUrl del archivo .env.

    Tu directorio src/api ahora debería incluir el nuevo archivo:

    • .env
    • astro.config.mjs
    • package.json
    • Directorysrc/
      • Directoryapi/
        • drupal.ts
      • types.ts
  3. En ese mismo archivo, crea la función fetchUrl para realizar la solicitud de obtención y deserializar la respuesta.

    src/api/drupal.ts
    import { Jsona } from "jsona";
    import { DrupalJsonApiParams } from "drupal-jsonapi-params";
    import type { DrupalNode } from "../types.ts";
    import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
    // Obtener la URL base de Drupal.
    export const baseUrl: string = import.meta.env.DRUPAL_BASE_URL;
    /**
    * Obtener url de Drupal.
    *
    * @param url
    *
    * @return Promise<TJsonaModel | TJsonaModel[]> como Promise<any>
    */
    export const fetchUrl = async (url: string): Promise<any> => {
    const request: Response = await fetch(url);
    const json: string | TJsonApiBody = await request.json();
    const dataFormatter: Jsona = new Jsona();
    return dataFormatter.deserialize(json);
    };
  4. Crea la función getArticles() para obtener todos los artículos publicados.

    src/api/drupal.ts
    import { Jsona } from "jsona";
    import { DrupalJsonApiParams } from "drupal-jsonapi-params";
    import type { DrupalNode } from "../types.ts";
    import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
    // Obtener la URL base de Drupal.
    export const baseUrl: string = import.meta.env.DRUPAL_BASE_URL;
    /**
    * Obtener url de Drupal.
    *
    * @param url
    *
    * @return Promise<TJsonaModel | TJsonaModel[]> como Promise<any>
    */
    export const fetchUrl = async (url: string): Promise<any> => {
    const request: Response = await fetch(url);
    const json: string | TJsonApiBody = await request.json();
    const dataFormatter: Jsona = new Jsona();
    return dataFormatter.deserialize(json);
    };
    /**
    * Obtener todos los artículos publicados.
    *
    * @return Promise<DrupalNode[]>
    */
    export const getArticles = async (): Promise<DrupalNode[]> => {
    const params: DrupalJsonApiParams = new DrupalJsonApiParams();
    params.addFields("node--article", ["title", "path", "body", "created"]).addFilter("status", "1");
    const path: string = params.getQueryString();
    return await fetchUrl(baseUrl + "/jsonapi/node/article?" + path);
    };

    Ahora puedes usar la función getArticles() en un componente .astro para obtener todos los artículos publicados con datos para cada título, cuerpo, ruta y fecha de creación.

  5. Ve a la página Astro donde obtendrás datos de Drupal. El siguiente ejemplo crea una página de inicio de artículos en src/pages/articles/index.astro.

    Importa las dependencias necesarias y obtén todas las entradas de Drupal con un tipo de contenido de article usando getArticles(), mientras pasas la interfaz DrupalNode para tipar tu respuesta.

    src/pages/articles/index.astro
    ---
    import { Jsona } from "jsona";
    import { DrupalJsonApiParams } from "drupal-jsonapi-params";
    import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../../types";
    import { getArticles } from "../../api/drupal";
    // Obtener todos los artículos publicados.
    const articles = await getArticles();
    ---

    Esta llamada de obtención usando getArticles() devolverá una matriz tipada de entradas que se pueden usar en tu plantilla de página.

    Tu directorio src/pages/ ahora debería incluir el nuevo archivo, si usaste el mismo archivo de página:

    • .env
    • astro.config.mjs
    • package.json
    • Directorysrc/
      • Directoryapi/
        • drupal.ts
      • Directorypages/
        • Directoryarticles/
          • index.astro
      • types.ts
  6. Agrega contenido a tu página, como un título. Usa articles.map() para mostrar tus entradas de Drupal como elementos de línea en una lista.

    src/pages/articles/index.astro
    ---
    import { Jsona } from "jsona";
    import { DrupalJsonApiParams } from "drupal-jsonapi-params";
    import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../types";
    import { getArticles } from "../api/drupal";
    // Obtener todos los artículos publicados.
    const articles = await getArticles();
    ---
    <html lang="en">
    <head>
    <title>My news site</title>
    </head>
    <body>
    <h1>My news site</h1>
    <ul>
    {
    articles.map((article: DrupalNode) => (
    <li>
    <a href={article.path.alias.replace("internal:en/", "")}>
    <h2>{article.title}</h2>
    <p>Published on {article.created}</p>
    </a>
    </li>
    ))
    }
    </ul>
    </body>
    </html>

Generación de publicaciones de blog individuales

Sección titulada Generación de publicaciones de blog individuales

Usa el mismo método para obtener tus datos de Drupal como arriba, pero esta vez, en una página que creará una ruta de página única para cada artículo.

Este ejemplo utiliza el modo estático predeterminado de Astro y crea un archivo de página de enrutamiento dinámico con la función getStaticPaths(). Esta función se llamará en tiempo de compilación para generar la lista de rutas que se convierten en páginas.

  1. Crea un nuevo archivo src/pages/articles/[path].astro e importa la interfaz DrupalNode y getArticle() desde src/api/drupal.ts. Obtén tus datos dentro de una función getStaticPaths() para crear rutas para tu blog.

    src/pages/articles/[path].astro
    ---
    import { Jsona } from "jsona";
    import { DrupalJsonApiParams } from "drupal-jsonapi-params";
    import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../../types";
    import { getArticles } from "../../api/drupal";
    // Obtener todos los artículos publicados.
    export async function getStaticPaths() {
    const articles = await getArticles();
    }
    ---

    Tu directorio src/pages/articles ahora debería incluir el nuevo archivo:

    • .env
    • astro.config.mjs
    • package.json
    • Directorysrc/
      • Directoryapi/
        • drupal.ts
      • Directorypages/
        • Directoryarticles/
          • index.astro
          • [path].astro
      • types.ts
  2. En el mismo archivo, asigna cada entrada de Drupal a un objeto con una propiedad params y props. La propiedad params se utilizará para generar la URL de la página y los valores props se pasarán al componente de la página como props.

    src/pages/articles/[path].astro
    ---
    import { Jsona } from "jsona";
    import { DrupalJsonApiParams } from "drupal-jsonapi-params";
    import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../../types";
    import { getArticles } from "../../api/drupal";
    // Obtener todos los artículos publicados.
    export async function getStaticPaths() {
    const articles = await getArticles();
    return articles.map((article: DrupalNode) => {
    return {
    params: {
    // Elige `path` para que coincida con el valor de enrutamiento `[path]`
    path: article.path.alias.split("/")[2],
    },
    props: {
    title: article.title,
    body: article.body,
    date: new Date(article.created).toLocaleDateString("es-ES", {
    day: "numeric",
    month: "long",
    year: "numeric",
    }),
    },
    };
    });
    }
    ---

    La propiedad dentro de params debe coincidir con el nombre de la ruta dinámica. Dado que el nombre del archivo es [path].astro, el nombre de la propiedad pasada a params debe ser path.

    En nuestro ejemplo, el objeto props pasa tres propiedades a la página:

    • title: una cadena, que representa el título de tu publicación.
    • body: una cadena, que representa el contenido de tu entrada.
    • date: una marca de tiempo, basada en la fecha de creación de tu archivo.
  3. Usa los props de la página para mostrar tu publicación de blog.

    src/pages/articles/[path].astro
    ---
    import { Jsona } from "jsona";
    import { DrupalJsonApiParams } from "drupal-jsonapi-params";
    import type { TJsonApiBody } from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../../types";
    import { getArticles } from "../../api/drupal";
    // Obtener todos los artículos publicados.
    export async function getStaticPaths() {
    const articles = await getArticles();
    return articles.map((article: DrupalNode) => {
    return {
    params: {
    path: article.path.alias.split("/")[2],
    },
    props: {
    title: article.title,
    body: article.body,
    date: new Date(article.created).toLocaleDateString("es-ES", {
    day: "numeric",
    month: "long",
    year: "numeric",
    }),
    },
    };
    });
    }
    const { title, date, body } = Astro.props;
    ---
    <html lang="en">
    <head>
    <title>{title}</title>
    </head>
    <body>
    <h1>{title}</h1>
    <time>{date}</time>
    <article set:html={body.value} />
    </body>
    </html>
  4. Navega a la vista previa de tu servidor de desarrollo y haz clic en una de tus publicaciones para asegurarte de que tu ruta dinámica esté funcionando.

Para desplegar tu sitio web, visita nuestras guías de despliegue y sigue las instrucciones para tu proveedor de alojamiento preferido.

Más guías de CMS

Contribuir Comunidad Patrocinador