Uso del módulo Views Remote Data para obtener datos de CKAN
El módulo Views Remote Data permite integrar y mostrar datos de fuentes externas en tus vistas.
NOTA: En mi caso, voy a explicar como he integrado y mostrado un listado de datasets de CKAN, pero esto es aplicable para cualquier petición a API
El primer paso es descargar e activar Views Remote Data:
- Descargar módulo:
composer require 'drupal/views_remote_data:^1.0'
Dentro del módulo contrib Views Remote Data, existen 2 módulos de prueba, PokeAPI y Test, con ellos puedes probar como funciona Views Remote Data y cómo replicar su uso en el código (De hecho, tomando estos 2 módulos de referencia he desarrollado el módulo personalizado que voy a explicar a continuación).
Puedes ver el módulo de testing PokeAPI aquí, o, una vez descargado Views Remote Data, hay otra forma de acceder a estos módulos prueba o testing en tu código, accediendo a web/modules/contrib/views_remote_data/tests/modules/ . Aquí encontrarás los dos módulos de prueba PokeAPI y Test.
Para activar estos módulos y que sean visibles por Drupal puedes seguir los pasos que explicamos en nuestra publicación Activar módulos de prueba en Drupal.
Importante tener en cuenta que algunos módulos de prueba tienen los tipos de contenidos y vistas definidos dentro de la carpeta config/install (todos son archivos YML), de manera que se crean cuando se instala el módulo de prueba (como en el caso de los módulos de prueba en Views Remote Data), en mi caso voy a explicar el proceso creando estas vistas y tipos de contenido desde la administración de Drupal antes de empezar (Tengo un tipo de contenido Dataset con un campo Slug tipo string). Esto se puede realizar de ambas formas.
Ahora, el siguiente paso sería:
- Activar módulo:
drush en views_remote_data
Una vez que tengamos el módulo descargado y activado hay que crear el tipo de contenido donde vas a asignar la respuesta de la API. En mi caso como quiero hacer un listado de datasets ya que este es el resultado de mi petición CKAN, tengo que ir a /admin/structure/types/add y crear el tipo de contenido “Datasets”. Luego en /admin/structure/types/manage/dataset/fields hay que crear los campos que necesites para mostrar el listado de datasets, en mi caso solo uno, el campo “Slug” de tipo Link (para redirigir al detalle del dataset en la página de CKAN) aparte del título, que viene por defecto.

Luego, hay que crear un módulo personalizado que gestione los datos de la petición API usando hooks y clases que suministra el módulo Views Remote Data.
drush generate module
Una vez generado el módulo, hay que modificar el archivo .info.yml y añadir las siguientes dependencias y parámetros necesarios.
dependencies:
- drupal:node
- drupal:file
- drupal:image
- views_remote_data:views_remote_data
version: '1.0.3'
project: 'views_remote_data'
datestamp: 1719349726
core_version_requirement: ^10 || ^11
Ahora, vamos a revisar la estructura de nuestro módulo para que quede de la siguiente forma (en mi caso, el nombre de mi módulo es views_remote_data_ckan)
- views_remote_data_ckan/
- src/
- EventSubscriber/
- ViewsRemoteDataSubscriber.php
Este archivo es el subscriber, que es el encargado de manejar las peticiones (aunque, en mi caso, las peticiones se gestionan en el servicio CKAN.php) y los datos que devuelve a la vista a través de sus métodos OnLoadEntities y OnQuery - CKAN.php
Este archivo es el servicio que se encarga de realizar las peticiones a APIs externas y devolver el resultado en el formato correcto.
- ViewsRemoteDataSubscriber.php
- EventSubscriber/
- views_remote_data_ckan.info.yml
Información general del módulo - views_remote_data_ckan.services.yml
En este archivo indica la ruta de los servicios que va a utilizar tu módulo personalizado, sean propios (como en mi caso, CKAN.php) o externos (como @http_client) - views_remote_data_ckan.views.inc
Este archivo tiene como funcionalidad definir y/o integrar los datos en las vistas a través de hooks.
- src/
Una vez que ya sabemos que estructura debemos tener y que función tiene cada archivo, voy a pasar a explicar cada uno de ellos en detalle.
views_remote_data_ckan.info.yml
name: 'Views Remote Data: CKAN'
type: module
description: 'Example module using Views Remote Data and the CKAN'
package: CKAN
dependencies:
- drupal:node
- drupal:file
- drupal:image
- views_remote_data:views_remote_data
# Information added by Drupal.org packaging script on 2024-06-25
version: '1.0.3'
project: 'views_remote_data'
datestamp: 1719349726
core_version_requirement: ^10 || ^11
views_remote_data_ckan.services.yml
services:
views_remote_data_ckan.ckan:
class: Drupal\views_remote_data_ckan\CKAN
arguments: ['@http_client', '@cache.data']
views_remote_data_ckan.event_subscriber:
class: Drupal\views_remote_data_ckan\EventSubscriber\ViewsRemoteDataSubscriber
arguments: ['@views_remote_data_ckan.ckan']
tags:
- { name: event_subscriber }
views_remote_data_ckan.views.inc
<?php
/**
* @file
* Provide views data for the CKAN.
*/
declare(strict_types=1);
/**
* Implements hook_views_data().
*/
function views_remote_data_ckan_views_data(): array {
$data = [];
$data['views_remote_data_ckan']['table']['group'] = 'views_remote_data_ckan';
$data['views_remote_data_ckan']['table']['entity type'] = 'node';
$data['views_remote_data_ckan']['table']['entity revision'] = FALSE;
$data['views_remote_data_ckan']['table']['base'] = [
'title' => 'CKAN',
'query_id' => 'views_remote_data_query',
];
return $data;
}
CKAN.php
<?php
declare(strict_types=1);
namespace Drupal\views_remote_data_ckan;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Cache\CacheBackendInterface;
use GuzzleHttp\Client;
/**
* The CKAN client.
*/
final class CKAN {
/**
* The HTTP client.
*
* @var \GuzzleHttp\Client
*/
private Client $client;
/**
* The cache backend.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
private CacheBackendInterface $cache;
/**
* Constructs a new PokeApi object.
*
* @param \GuzzleHttp\Client $client
* The HTTP client.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The cache backend.
*/
public function __construct(Client $client, CacheBackendInterface $cache) {
$this->client = $client;
$this->cache = $cache;
}
public function getDatasets()
{
return $this->get("https://demo.ckan.org/api/3/action/current_package_list_with_resources");
}
/**
* Gets results from the API.
*
* @param string $uri
* The uri.
*
* @return array
* The resultCKAN
*/
public function get(string $uri): array {
// Comprueba que la URL y la respuesta no están guardados en la memoria caché
$cache_key = "ckan:$uri";
if ($cache = $this->cache->get($cache_key)) {
return $cache->data;
}
try {
$response = $this->client->get($uri); // Petición AJAX
$data = Json::decode((string) $response->getBody()); // Transformación a array asoc.
$this->cache->set($cache_key, $data); // Guarda los datos en la caché
return $data;
}
catch (CKAN $e) {
return [];
}
}
}
Este servicio se encarga de hacer las llamadas y devolver la respuesta al subscriber en formato de array asociativo.
$this->client = $client: Se espera que se pase un objeto de tipo Client. Este objeto podría ser un cliente HTTP para hacer solicitudes a una API.
$this->cache = $cache: Se esperá que se le pase un objeto de tipo CacheBackendInterface para guardar respuestas APIs, objetos… y mejorar el rendimiento.
método get(): Este método recibe una URL en su parámetro $uri, comprueba que esta URL no esté en la memoria caché junto a sus datos, si es así, devuelve los datos directamente ahorrando hacer la petición, en el caso de que no estén guardados los datos en la memoria caché, realizará la petición, obtendrá los datos, los convertirá de JSON a un array asociativo y los devolverá (además de guardar los datos y la URL en la memoria caché).
método getDatasets(): Este método llama al anterior método get() pasándole la URL de los datatsets de CKAN como parámetro.
ViewsRemoteDataSubscriber.php
<?php
declare(strict_types=1);
namespace Drupal\views_remote_data_ckan\EventSubscriber;
use Symfony\Component\HttpFoundation\Request;
use Drupal\file\Entity\File;
use Drupal\node\Entity\Node;
use Drupal\views\ResultRow;
use Drupal\views_remote_data\Events\RemoteDataLoadEntitiesEvent;
use Drupal\views_remote_data\Events\RemoteDataQueryEvent;
use Drupal\views_remote_data_ckan\CKAN;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Test subscriber for populating values in test views.
*/
final class ViewsRemoteDataSubscriber implements EventSubscriberInterface {
/**
* The CKAN client.
*
* @var \Drupal\views_remote_data_ckan\CKAN
*/
private CKAN $ckan;
/**
* Constructs a new ViewsRemoteDataSubscriber object.
*
* @param \Drupal\views_remote_data_ckan\CKAN $ckan
* The CKAN client.
*/
public function __construct(CKAN $ckan) {
$this->ckan = $ckan;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
return [
RemoteDataQueryEvent::class => 'onQuery',
RemoteDataLoadEntitiesEvent::class => 'onLoadEntities',
];
}
/**
* Subscribes to populate entities against the results.
*
* @param \Drupal\views_remote_data\Events\RemoteDataLoadEntitiesEvent $event
* The event.
*
* @todo need tests which test this.
*/
public function onLoadEntities(RemoteDataLoadEntitiesEvent $event): void {
$supported_bases = [
'views_remote_data_ckan',
];
$base_tables = array_keys($event->getView()->getBaseTables());
if (count(array_intersect($supported_bases, $base_tables)) > 0) {
foreach ($event->getResults() as $result) {
assert(property_exists($result, 'title'));
$node = Node::create([
'title' => $result->title['#title'],
'type' => 'dataset',
'field_slug' => [
'uri' => $result->title['#url'],
'title' => $result->title['#title'],
],
]);
$result->_entity = $node;
}
}
}
/**
* Subscribes to populate the view results.
*
* @param \Drupal\views_remote_data\Events\RemoteDataQueryEvent $event
* The event.
*/
public function onQuery(RemoteDataQueryEvent $event): void {
$supported_bases = [
'views_remote_data_ckan',
];
$base_tables = array_keys($event->getView()->getBaseTables());
if (count(array_intersect($supported_bases, $base_tables)) > 0) {
$datasets = $this->ckan->getDatasets();
foreach ($datasets['result'] as $dt) {
$result_row = new ResultRow([
'title' => [
'#type' => 'link',
'#title' => $dt['title'],
'#url' => $dt['name'],
],
]);
$event->addResult($result_row);
}
}
}
Una vez que tengamos el módulo listo y hayamos entendido todo su contenido, nos falta crear la vista en /admin/structure/views/add. El tipo de vista que debe establecer es el que estableció en la propiedad title del archivo views_remote_data_ckan.views.inc.

Una vez que hayas creado la vista, el siguiente paso es configurar los campos que deseas mostrar. Aquí te explicamos cómo hacerlo:
- Acceder a la Configuración de Campos: Dirígete a la sección de Fields (Campos) en la interfaz de configuración de la vista. Esta sección es donde podrás agregar y gestionar los campos que se mostrarán en el resultado de tu vista.
- Agregar Campos:
- Opción 1: Usando "Rendered Entity": Puedes optar por agregar todos los campos del tipo de contenido utilizando la opción Rendered entity. Esta opción te permite incluir el contenido completo del tipo de entidad seleccionado (por ejemplo, un nodo). Esto es útil si deseas mostrar todos los campos asociados a un tipo de contenido sin tener que configurarlos uno a uno.
- Opción 2: Seleccionando Campos Específicos: Si prefieres tener un control más granular sobre qué campos se muestran y cómo se configuran, puedes agregar campos individualmente. Para ello, selecciona Add (Agregar) en la sección de Fields y elige la opción Property value.
- Configuración de Campos Específicos:
- Al seleccionar un campo específico, tendrás la opción de configurarlo. Una de las opciones más útiles es Property value. Esta opción te permite acceder a propiedades específicas del objeto que estás utilizando en la vista.
- En el campo Property path from incoming object, debes indicar la ruta que lleva a la propiedad que deseas mostrar. Por ejemplo, si quieres acceder a la URL del dataset, la ruta que utilizarías sería title.#url. Esto significa que estás accediendo a la propiedad url del objeto title definidos dentro de nuestro ResultRow en el archivo ViewsRemoteDataSubscriber.php.

En mi caso, he utilizado Property values para poder acceder a la config. de cada campo de forma independiente, por esto, desde las opciones que proporciona Property value sobre el campo Slug que hemos creado anteriormente, podemos marcar que el campo se muestre como un enlace. Y, en Link path establecemos la URL del enlace (en mi caso ckan-list/{slug}).
El {slug} se puede obtener dentro de la pestaña “Rewrite Results” (está en la parte inferior de las opciones cuando se pincha sobre el property value)

El resultado final debería ser el siguiente:
Página

Vista

Preview Vista
