L’API REST du plugin « REST Factory »
L’API ezrest
Le plugin REST Factory implémente une API dénommée ezrest
conformément au cadre défini par le plugin «Serveur HTTP abstrait». De fait, les URL sont du type /http.api/ezrest/…
et le fichier http/ezrest.php
contient l’ensemble des fonctions nécessaires au fonctionnement de l’API.
Pour simplifier la mise en place d’API REST au-delà de ce que propose le plugin Serveur HTTP abstrait, REST Factory définit un cadre standard pour gérer les collections et ressources au travers de son API : vérification, traitement de données et configuration sont standardisés pour convenir à la plupart des besoins et, des points d’entrée spécifiques permettent de personnaliser le fonctionnement proposé par défaut. Les réponses sont toujours fournies au format JSON.
Dans cette version du plugin, seule la méthode GET pour une collection ou une ressource est mise à disposition. Il est aussi possible de récupérer l’index de toutes les collections disponibles.
Les collections
Une collection possède un identifiant unique de type chaine qui en général décrit l’objet au pluriel comme plugins
ou categories
.
Une collection est fournie par un plugin utilisateur de REST Factory : il déclare sa configuration et propose les services idoines permettant de vérifier les requêtes sur cette collection et d’en récupérer les données.
Les ressources
Une ressource est un objet particulier d’une collection désignée par un identifiant unique qui permet d’accéder à l’objet en base de données : par exemple, l’id pour un article ou le préfixe pour un plugin.
C’est la configuration qui indique si la collection accepte la lecture d’une ressource et si oui au travers de quel identifiant (un plugin peut être identifié par son id ou son préfixe). Il n’est pas toujours utile de proposer l’accès à une ressource précise (dépend des informations disponible sur l’objet). C’est le cas, par exemple, de la collection des catégories.
Les basiques de REST Factory
Pour implémenter une API REST limitée à la méthode GET sur les collections et les ressources, le Serveur HTTP abstrait requiert le codage de la liste des fonctions suivantes :
-
http_ezrest_get_index_dist
-
http_ezrest_get_collection_dist
-
http_ezrest_get_ressource_dist
-
http_ezrest_erreur_dist
Un plugin utilisateur de REST Factory n’aura donc jamais à se préoccuper de ces fonctions, qui sont écrites une fois pour toute. Ces fonctions font appel à des services standardisés pour effectuer les vérifications idoines de chaque requête et constituer la réponse. Certains de ces services sont personnalisables par les plugins utilisateur comme décrit plus avant.
Le plugin REST Factory ne propose aucune collection par défaut mais attend des plugins utilisateur qu’ils déclarent les collections utilisables au travers d’un pipeline nommé liste_ezcollection
.
Déclaration des collections
La configuration d’une collection se matérialise par un tableau associatif dont les index sont expliqués ci-dessous.
Paramètres généraux | |
module | Préfixe du plugin fournissant la collection (obligatoire) |
cache | Tableau de gestion des caches, ce qui revient à définir la méthode de peuplement des données. Voir le bloc «Paramètres du bloc cache» pour le détail. |
cle | Tableau de définition d’une clé d’autorisation d’accès à l’API (facultatif). Voir le bloc «Paramètres du bloc cle» pour le détail. |
filtres | Tableau, éventuellement vide, des filtres autorisés sur la collection. Voir le bloc «Paramètres d’un filtre» pour le détail. |
sans_condition | Indique si REST Factory doit calculer les conditions SQL associées aux filtres (facultatif). |
ressource | Champ identifiant la ressource de façon unique dans la table matérialisant la collection et servant à la désigner dans l’url. Par exemple, le préfixe pour les plugins (facultatif). |
Paramètres du bloc cache | |
type | Type de cache utilisé (revient à définir la méthode de peuplement des données). Prend les valeurs ’ezrest’ pour la méthode PHP et ’spip’ pour la méthode par squelette (obligatoire pour un cache). |
duree | Durée en secondes de conservation du cache (facultatif). Si absent, la durée par défaut des caches REST Factory est utilisée (1 jour). |
Paramètres du bloc cle | |
nom | Nom du paramètre d’URL matérialisant la clé d’accès (obligatoire). |
format | Expression régulière définissant le format de la clé. |
Paramètres d’un filtre | |
critere | Nom du filtre dans l’URL. Peut coïncider ou pas au champ dans la table (obligatoire pour un filtre). |
est_obligatoire | Indique si le filtre doit toujours être utilisé lors d’une requête sur la collection ou pas (facultatif, défaut à false). |
vide_interdit | Indique si le critère accepte ou pas une valeur vide (facultatif, défaut à false). |
sans_condition | Indique si REST Factory doit calculer la condition SQL associée au filtre (facultatif, défaut à false). |
hors_contenu | Indique si le filtre a une influence sur le contenu de la réponse ou pas. Si le filtre a une influence sur le contenu, il est utilisé pour calculer l’identifiant du cache et, en cas de cache spip, il est fourni au contexte du squelette HTML (facultatif, défaut à false). |
module | Préfixe du plugin fournissant le filtre. Il est en effet possible qu’un plugin utilisateur ne fournisse qu’un filtre supplémentaire dû au fait qu’il rajoute une colonne à la table ou autre. Ce module prévaut sur le module général de la collection (facultatif). |
champ_nom | Désigne le nom du champ de la table représentant le critère. Ce paramètre ne sert qu’au plugin utilisateur pour construire la condition de lecture de la collection. Omis si le paramètre critère désigne déjà le champ de la table (facultatif). |
champ_type | Fournit le type PHP du champ, soit ‘string’ ou ‘int’. Cela permet à REST Factory d’utiliser sql_quote() ou intval() pour traiter la valeur dans la condition. Par défaut, le type est considéré comme une chaine (facultatif). Cette configuration est aujourd’hui dépréciée car sql_quote() sait repérer le type du champ concerné. |
champ_table | Permet à REST Factory de préfixer les champs des conditions SQL par le nom SPIP de la table. Ce champ indique l’objet au pluriel. Si il est omis, REST Factory utilise le nom de la collection et si celui-ci ne mène pas à une table, aucun préfixe n’est ajouté. De même, si il est affecté à une chaine vide aucun préfixe n’est ajouté (facultatif). |
format | Expression régulière définissant la syntaxe de la valeur du critère (facultatif, défaut à ’’). |
L’identifiant de la collection ne fait pas partie du bloc de configuration car il est passé comme index du tableau global de toutes les collections. Cet identifiant est une chaine qui représente en général un type d’objet au pluriel (par exemple, plugins). La déclaration de la collection pays se fait comme suit :
$collections['pays'] = array(
'module' => 'isocode',
'cache' => array(
'type' => 'ezrest',
'duree' => 3600 * 24 * 30
),
'filtres' => array(
array(
'critere' => 'region',
'est_obligatoire' => false,
'champ_nom' => 'code_num_region',
'champ_table' => 'iso3166countries'
),
array(
'critere' => 'continent',
'est_obligatoire' => false,
'champ_nom' => 'code_continent',
'champ_table' => 'iso3166countries'
),
),
'ressource' => 'code_alpha2'
);
Un plugin utilisateur n’est pas obligé de fournir uniquement des collections entières mais peut parfois ne rajouter qu’un filtre. C’est le cas du plugin «SVP Typologie» qui permet de filtrer la collection plugins, fournie par SVP API, sur la catégorie. Dans ce cas, il est nécessaire de s’assurer que la collection de base a bien été déclarée au préalable dans la séquence du pipeline.
Les services de personnalisation de l’API
Pour un plugin utilisateur, on distingue les services liés à une collection et ceux non liés à une collection. C’est cette distinction qui régit le nommage des services du plugin utilisateur.
Les services de personnalisation d’un plugin utilisateur doivent être fournis dans le fichier ezrest/${prefixe}.php
, où ${prefixe}
désigne le préfixe du plugin utilisateur.
Les services non liés à une collection
Ces services sont tous facultatifs. Il convient à chaque plugin utilisateur de définir l’intérêt de les fournir ou pas. ${prefixe}
désigne le préfixe du plugin utilisateur.
${prefixe}_api_verifier_contexte |
Détermine si le serveur est capable de répondre aux requêtes (par exemple, un contexte de configuration). REST Factory ne fait aucune vérification par défaut. |
${prefixe}_reponse_informer_plugin |
Ajoute des informations au bloc ’fournisseur’ de la réponse |
${prefixe}_reponse_expliquer_erreur |
Permet de modifier le bloc d’erreur après qu’il ait été complètement finalisé. A éviter. |
Les services liés à une collection
${collection}_collection_verifier |
Détermine si la collection demandée est valide et renvoie un bloc d’erreur mis à jour. REST Factory vérifie au préalable que la collection est bien déclarée. |
${collection}_verifier_filtre_${critere} |
Détermine si le filtre de critère ${critere} est valide pour la collection ${collection} et renvoie un bloc d’erreur mis à jour. REST Factory vérifie au préalable les filtres obligatoires et que chaque filtre est bien déclarée |
${collection}_verifier_ressource_${champ} |
Détermine si la ressource identifiée par le champ ${champ} est valide pour la collection ${collection} . REST Factory vérifie au préalable que la collection autorise bien l’accès à une ressource |
${collection}_conditionner_${critere} |
Calcule la condition SQL associée au filtre de critère ${critere} pour la collection ${collection} . REST Factory sait calculer des conditions simples à partir de la configuration du filtre. Cette fonction est à coder uniquement dans des cas complexes. |
${collection}_collectionner |
Renvoie les données en réponse à la requête de lecture de la collection ${collection} . Par défaut, REST Factory ne fait rien, tout est du ressort du plugin utilisateur. |
${collection}_ressourcer |
Renvoie les données en réponse à la requête de lecture d’une ressource de la collection ${collection} . Par défaut, REST Factory ne fait rien, tout est du ressort du plugin utilisateur. |
Les méthodes de peuplement des données
Le peuplement de l’index donnees
de la réponse peut se faire, soit en PHP au travers des fonctions de service spécifiques du plugin utilisateur ${prefixe}_collectionner()
ou ${prefixe}_ressourcer()
, soit en utilisant un squelette spécifique appelé par la fonction recuperer_fond()
et de chemin ezrest/json/${prefixe}_${collection}.html
pour les requêtes de type collection et ressource.
Ce squelette doit construire la chaine JSON valide correspondant aux données spécifiées par la requête et être en capacité de renvoyer la collection ou une ressource de la collection. La chaine JSON est ensuite décodée par REST Factory pour être intégrée dans la réponse.
Le choix de la méthode est définie dans la configuration de la collection.
La gestion des caches
Pour éviter de solliciter la base de données à chaque requête, REST Factory utilise des caches pour stocker pendant une durée limitée les données issues des fonctions PHP de chargement des données ou des squelettes HTML.
Si la requête utilise un squelette HTML pour peupler les données, REST Factory ne fait rien d’autre que de se reposer sur la gestion des caches de SPIP. Si la requête utilise une fonction PHP comme ${prefixe}_collectionner()
, REST Factory utilise un cache propre géré par le plugin Cache Factory dont la durée de conservation est définie par la configuration de la collection.
Les caches propres à REST Factory sont stockés dans un sous-répertoire du répertoire local/cache-ezrest/
, sous-répertoire au nom du plugin fournisseur de la collection. L’index des collections fournis par REST Factory est stocké dans le sous-répertoire ezrest/
. Le nom des caches est composé de deux composants obligatoires, type_requête
et collection
, et d’un composant facultatif, complement
, recevant soit la valeur md5 de la ressource, soit la liste des filtres concaténée et cryptée par md5. Le cache de la collection pays se nomme collection_pays.json
et celui de la ressource SVP de la collection plugins ressource_plugins_0fea6a13c52b4d4725368f24b045ca84.json
.
REST Factory gère également un index des caches, local/cache-ezrest/index.txt
, pour afficher correctement dans le formulaire de vidage la correspondance du md5. Cet index est créé et modifié lors du passage dans le pipeline post_cache
.
Cette gestion des caches « serveur » ne doit pas être confondue avec la nécessité, pour les clients, de limiter le nombre de requêtes adressées en gérant de leur côté un cache « client » sous une forme adéquate.
Les pipelines post_ezcollection
et post_ezressource
Suite à l’appel des services de récupération des données, ezrest_collectionner()
et ezrest_ressourcer()
, les fonctions REST de traitement d’un GET sur une collection ou une ressource font appel à un pipeline respectivement post_ezcollection
et post_ezressource
. Ces pipelines permettent à un plugin de compléter l’ensemble des données récupérées.
La gestion des erreurs
REST Factory simplifie aussi la gestion des erreurs pour les plugins utilisateur. En effet, ceux-ci n’ont jamais à se préoccuper de remplir le bloc d’erreur complet mais se contentent, en général, de fournir un titre, un détail voir le type de l’erreur. Les index modifiables du bloc d’erreur dépendent du service.
Le format des items de langue est imposé par REST Factory et se déduit des index du bloc d’erreur. Seul les index titre et detail du bloc d’erreur sont concernés. Les formats sont les suivants, respectivement pour le titre et le détail :
${prefixe}:erreur_${statut}_${type}_titre
${prefixe}:erreur_${statut}_${type}_message
Pour aller plus loin
Pour aller plus loin dans la compréhension du plugin et de son utilisation, un guide en PDF est fourni avec le code.
Discussions by date of activity
2 discussions
J’implémente une API manuellement, en utilisant REACT comme front-end et SPIP comme back-end. Si quelqu’un est intéressé, je peux collaborer à la mise en œuvre.
J’ai réussi à implémenter les deux et ça a été excellent !
“Estoy implementado una Api manualmente, utilizando REACT como frond-end, y SPIP como Back-end. Si alguien esta interezado le puedo colaborar con la implementacón.
Logre implementarla ambos y me ha ido excelente!!”
J’avais la même idée pour VueJS. Mais pour l’instant j’ai un problème. Mon API REST fonctionne en local (sur deux postes avec Apache). Mais pas sur le serveur de production (un RPI4 sous proxy NGINX mais je n’ai pas la main sur la conf NGINX). SPIP me renvoie une page 404 alors que les dépôts sont les mêmes (mêmes version de SPIP, mêmes plugins, même BDD). Quelqu’un aurait une idée ?
https://infojune.fr/http.api/ezrest/
Hello,
As-tu vérifié ton htaccess ?
Merci pour ta réponse Eric. J’ai effectivement pensé au .htaccess. Mais j’ai le même fichier sous Windows/Apache que sous Linux/Nginx. Je me suis dit qu’il était peut-être ignoré sous Windows/Apache alors je suis allé voir dedans. A priori, c’est celui d’origine. J’ai essayé de commenter la ligne qui concerne les APIs pour voir mais sans résultat :
https://pastebin.com/0q87WTtB
Ok, non mais la ligne sur l’api est la bonne. Parfois on oublie d’activer le .htaccess à partir du fichier htaccess.txt mais a priori c’est pas le souci.
J’avoue qu’à distance je ne vois pas ce qui peut poser problème surtout si tu arrives à faire fonctionner l’api en local.
En fait, c’est tout simplement que NGINX ne supporte pas les .htaccess ^^
Ce n’était donc pas l’environnement Windows/Apache qui ignorait le .htaccess mais l’environnement Linux/NGINX.
Donc la règle à mettre à la racine du vhost dans NGINX :
rewrite ^/([w] ).api([/.](.*))?$ /spip.php?action=api_$1&arg=$3 last;
4 mois après je rebondis sur ce message.
Je ne sais pas si la syntaxe change en fonction de la version du server mais cette dernière règle ne fonctionne pas chez moi, en Nginx 1.18
J’ai un nginx: [emerg] invalid number of arguments in “rewrite” directive qui empêche le serveur de redémarrer ... 🤔
OK, c’est résolu. La bonne syntaxe est en réalité la suivante (il faut mettre la ligne dans un bloc
location { ... }
sinon ça ne fonctionne pas.)Du coup j’ai mis à jour le wiki
Reply to this message
Si on crée dynamiquement la liste des collections à exposer dans le pipeline
liste_ezcollection
(par ex en récupérant la liste des collections via lire_config()), est-ce que ça fonctionnerait bien en cas de modification des collections à exposer ou il faudrait supprimer un cache ou qqe chose du genre ?Même question avec des fonctions dynamiques du type :
Je me demandais d’ailleurs s’il n’aurait pas été plus judicieux d’écrire les fonctions comme ça dans ezREST. Par exemple :
et de splitter tout le fichier prefixe.php dans différents fichiers. Par exemple : prefixe_contexte.php, prefixe_reponses.php, prefixe_verifier.php, prefixe_collectionner.php et prefixe_ressourcer.php
Au pire, on doit pouvoir au moins splitter le fichier
prefixe.php
dans le plugin utilisateur grâce à desinclude
non ? Parce qu’il devient vitre très long ce fichier :pPour définir les collections à exposer vu que cela passe par le pipeline liste_ezcollection on peut lire une configuration meta ou autre, il n’y a pas de souci.
Pour les fonctions dynamiques faudrait essayer. Ce que je fais c’est que j’appelle dans le code ezREST une fonction d’api xxxx et que c’est elle qui aiguille vers la bonne fonction de service collection_xxxx ou prefixeplugin_xxxx suivant ce que l’on veut. Ces fonctions doivent être dans un include précis ezrest/prefixeplugin.php.
Sinon, il est toujours possible de splitter l’include des services en plusieurs sous-includes et d’y faire appel dans l’include parent oui.
Après, si tu as des besoins spécifiques il est toujours possible d’étudier des évolutions du plugin.
Autre chose, je te conseille de lire le guide conception qui est inclu dans le plugin «Guide - Le plugin REST Factory.pdf». Il est plus complet que cet article et donne des exemples d’utilisation.
Reply to this message
Add a comment
Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :
Merci d’avance pour les personnes qui vous aideront !
Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.
Follow the comments:
|
