Retour

Intégrer les données d'une API externe dans Drupal

Publié le
06.05.2026

Lorsque l'on souhaite utiliser Drupal pour gérer des données de sources externes, hormis les données chaudes, nous avons tout intérêt à les intégrer côté backend pour profiter du système d'affichage et de cache de Drupal. Votre client peut vous demander d'afficher ses points de vente sur une carte, de gérer un catalogue de produits ou encore de réaliser un annuaire.

Pour gérer ces cas différents, on peut se baser sur le même mécanisme : il faut synchroniser les données de l'api avec des entités miroir dans la base Drupal, de façon périodique. L'affichage de ces données est ensuite géré de manière native par Drupal en utilisant les vues, les modes d'affichage et les templates. Cet article a pour but de passer en revue les outils à notre disposition dans l'écosystème Drupal pour réaliser cette tâche.

Dans un premier temps, il va falloir créer la structure de données en choisissant le type d'entité à créer : type de contenu, vocabulaire, type d'entité custom, etc. Tout dépend de l'usage que souhaitez en faire mais le choix de l'entité porteuse de l'info ne diffère pas de la façon classique de concevoir un site en Drupal pour gérer des contenus uniquement contribués. Ce choix étant totalement lié au contexte métier, je ne m'attarderais pas dessus.

Le développement de cette fonctionnalité va s'articuler autour d'un module custom qui aura pour mission de :

  • gérer la connexion HTTP et les requêtes avec le serveur distant
  • mettre à disposition une commande Drush pour lancer des tâches automatisées
  • synchroniser les données (création/modification/suppression)

Quels fonctionnalités natives pour nous aider ?

  • Librairie Guzzle : un client HTTP qui va nous permettre de gérer la connexion avec l'API et de récupérer le flux de données.
  • Queue API : offre la possibilité de stocker les éléments à traiter dans une pile, ce qui peut être intéressant notamment pour les appels API paginés ou encore pour éviter d'utiliser la mémoire pour traiter des tableaux de données volumineux.
  • Batch API : permet de découper le traitement des données en lots de petite taille pour alléger les processus PHP et éviter les interruptions.
  • State API : permet de stocker et d'accéder de manière simple à des données. On peut s'en servir pour stocker la date de dernière exécution du traitement par exemple.
  • Module Monolog : ce module de la communauté implémente la librairie Monolog. Elle permet de créer de journaliser les exécutions dans des fichiers distincts.
  • Drush command : la possibilité de créer des commandes Drush personnalisées nous permettra de déclencher facilement la synchronisation depuis un terminal ou depuis le cron.

Un module dédié pour orchestrer l'ensemble

Pour cloisonner les développements, je conseille de réaliser un module custom qui englobera les développements en lien avec cette synchronisation. On peut évidemment découper davantage la solution, en isolant les fonctionnalités dans plusieurs modules custom pour faciliter la maintenance et la ré-utilisabilité. Tout dépend du contexte de développement : complexité métier, expérience des développeurs, etc.

Étapes de développement

1 Créer la structure de données

La première étape va consister à créer les types d'entités nécessaires à notre synchronisation. Pour les types natifs (types de contenus/vocabulaires), la manipulation se fera par l'interface d'administration de manière conventionnelle. Si vous avez besoin de types d'entités personnalisés, une commande drush est disponible et vous permettra de créer un module dédié.

mise en forme code :  drush generate content-entity

null

L'ajout des champs, y compris pour une entité custom, se fait par l'administration. Je conseille dans la mesure du possible d'utiliser des champs basiques (texte court non formaté, entier, etc.) et de ne pas utiliser de champs formatés. Cela permet de simplifier la création/mise à jour des champs par le code.

2 Créer une commande drush

Pour gérer l'automatisation de la synchronisation, il faudra créer une ou plusieurs commandes drush. Cela permettra de pouvoir lancer l'import en ligne de commande depuis n'importe quel environnement et donc de faire appel à ces commandes dans la CRONTAB. Avec la configuration xDebug adéquate, cette commande pourra être exécutée en pas à pas pour faciliter les étapes de développement.

Voici un code minimal pour la création d'une commande Drush, elle pourra être lancée par la commande :

drush api-import:synchronize

<?php

namespace Drupal\my_api_import_module\Commands;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drush\Commands\AutowireTrait;
use Drush\Commands\DrushCommands;

final class MyDrushCommand extends DrushCommands
{

    use AutowireTrait;

    public function __construct(private readonly EntityTypeManagerInterface $entityTypeManager)
    {
        parent::__construct();
    }

    /**
     * Commande de synchronisation des données de l'api.
     *
     * @command api-import:synchronize
     * @aliases api-sync
     * @usage api-import:synchronize
     */

    public function synchronizeData(): void
    {
        // Code métier. 
        // Appels à des services. 
    }
}


3 Créer une classe connecteur

La connexion avec l'api externe sera réalisée dans une classe de service. L'objectif est d'isoler la connection des autres traitements métiers pour obtenir un service purement technique. On pourra y découper la gestion des headers, si elle est complexe et y gérer l'authentification mais le traitement des données sera réalisé dans une autre classe.

<?php

namespace Drupal\my_api_import_module;

use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;

class ApiClient
{
    public function __construct(private readonly ClientInterface $httpClient)
    {
    }

    public function request()
    {
        try {
            $response = $this->httpClient->request('GET', 'https://api.externalsite.com/endpoint', ['headers' => ['Accept' => 'application/json', 'Content-type' => 'application/json',],]);
            return json_decode($response->getBody()->getContents(), true);
        } catch (RequestException $e) {
            // Gestion de l'erreur

            // Ajout dans monolog
            
            $e->getResponse();
        }
        return FALSE;
    }
}


4 Gérer la pagination

Toutes les api ne proposent pas de pagination, par conception ou à cause d'une quantité de données faible mais dans les autres cas, vous devrez faire en sorte de parcourir toutes les pages de résultats pour récupérer l'intégralité des données correspondant à la requête. Une bonne api vous fournira le nombre de données disponibles pour toutes les pages et le nombre de pages disponibles, voire le nombre de résultats de la page suivante.
Si ces informations ne sont pas présentes, le code devra parcourir les pages tant qu'elles proposent des résultats.

<?php
$queue = \Drupal::queue('my_module_import');
$page = 1;
$hasMore = TRUE;
while ($hasMore) {
    $response = $this->httpClient->request('GET', 'https://api.externalsite.com/endpoint', ['query' => ['page' => $page, 'per_page' => 50],]);
    $payload = json_decode((string)$response->getBody(), TRUE);
    foreach ($payload['data'] as $item) {
        // Ajout des données dans la queue, voir étape suivante
        $queue->createItem($item);
    }
    $hasMore = !empty($payload['items_on_next_page']);
    $page++;
}

5 Gérer la queue

L'utlisation de la queue permet de résoudre des problématiques qui interviennent lorsque la quantité de données à importer est conséquente. Une fois les données ajoutées à la queue, chaque élément sera traité de manière indépendante avec possibilité de reprise en cas d'interruption. L'utilisation de ce mécanisme permet également de séparer les appels http, pour récupérer les données, de la persistance des données. On comprend donc que cette brique est à mettre en place uniquement lorsque la volumétrie est importante. Pour traiter peu de données, un traitement synchrone sera amplement suffisant et simplifiera l'application.

On a vu à l'étape précédente que l'ajout des éléments se fait de manière simpliste. Pour exploiter ces données, l'utilisation du cron est adaptée puisqu'elle va nous permettre de traiter en tâche de fond les données récupérées de l'API. Pour cela, on créer un classe qui étend QueueWorkerBase. Cette classe sera scrutée par la tâche cron qu'il faudra configurer pour être lancée la nuit par exemple. C'est l'annotation @QueueWorker qui va permettre cette automatisation. Dans l'exemple suivant, le paramètre cron = {"time" = 30} définit le temps d'exécution de la Queue à chaque déclenchement du cron.

<?php

// @QueueWorker(
// id = "my_module_import",
// title = "Import distant",
// cron = {"time" = 30}
// )
class MyModuleImportWorker extends QueueWorkerBase
{
    public function processItem($item): void
    {
        // recherche d'une entité existante via un identifiant distant
        
        if ($exists) {
            // logique de mise à jour
        } else {
            // logique de création
        }
        // persistance de l'entité
    }
}

Gestion cron

Le cron devra être configuré sur la plateforme accueillant le drupal pour gérer à la fois la récupération des données et leur traitement dans un second temps. Il faudra créer deux entrées dans la crontab, une première pour déclencher la commande drush et une seconde pour traiter la queue.

Dans la partie sur la mise en place de la Queue, on a pu voir que le cron déclenchait la classe parce qu'elle était annotée. Le temps d'exécution défini dans cette annotation est à calibrer suivant vos besoins. Dans certains cas, une exécution unique de 30 secondes suffira mais pour beaucoup de données, il sera intéressant de faire un découpage. On pourra alors mettre en place dans la crontab un déclenchement toutes les 5 min pendant une heure. L'idéal étant de connaitre le temps d'exécution théorique de la synchronisation complète.

Conclusion

On a pu voir pourquoi et comment mettre en place un système de synchronisation de données externes sur un site en Drupal. La solution proposée n'est pas unique, il en existe d'autres. L'important est de calibrer la solution par rapport à la quantité de données, à la structure de l'api distante et au taux de rafraichissement des données attendu.

D’autres articles à découvrir