Ce plugin a pour but premier de normaliser des URL que l’on pourra appeler pour manipuler les données du site. À chaque URL, il cherche une fonction plus précise, qui va implémenter une fonctionnalité. Et il ne fait quasiment que cela : c’est à vous, développeuses et développeurs, d’implémenter ces fonctionnalités suivant l’API que vous cherchez à fournir.
Pour cela, il fournit une unique action « http.api » qui va gérer trois paramètres :
- un format : c’est le nom de l’API réellement implémentée
- une collection : le type des données qu’on veut utiliser, par exemple le nom d’un objet éditorial de SPIP
- une ressource : l’identifiant unique d’un contenu
Ces trois paramètres sont tout simplement ajoutés à la suite dans l’URL, séparés par des « / ». Seul le premier est toujours obligatoire, les autres sont ajoutés suivant ce que l’on veut manipuler. On se retrouve alors avec trois familles d’URL. Par exemple avec le format « atom » :
-
http://site.example/http.api/atom
désigne l’index du format, et peut être utilisé pour lister les collections réellement disponibles (si ce format prévoit ce genre d’index !) -
http://site.example/http.api/atom/articles
désigne la collection des articles, et doit donc fournir une liste de plusieurs articles, à priori tous s’il n’y a pas de paramètres de filtrages supplémentaires -
http://site.example/http.api/atom/articles/1234
désigne l’URL d’un article précis dans ce format
Pour chacun de ces URLs, on cherche enfin la méthode HTTP utilisée pour l’appeler : get, post, put ou delete. Suivant la conjonction de tous ces paramètres, le plugin appelle la bonne fonction.
Bien entendu, chaque développeur doit adapter ce cadre à l’API qu’il désire réellement implémenter.
Utilisation de la librairie HTTPFoundation
Petite précision : afin de ne pas gérer nous-mêmes les affres des requêtes et des réponses en HTTP, ce plugin intègre et utilise la librairie HTTPFoundation fournie par Symfony.
Vous trouverez la documentation de ce module par ici :
http://symfony.com/fr/doc/current/components/http_foundation/introduction.html
Ce plugin crée donc dès le début un objet Request et un objet Response, qui seront ensuite trimbalés et modifiés au fil du temps dans les fonctions d’implémentation.
Nos trois paramètres essentiels sont déjà ajoutés à l’objet Request dans la propriété des attributs persos :
-
$requete->attributes->get('format')
-
$requete->attributes->get('collection')
-
$requete->attributes->get('ressource')
Implémentation d’une API
Pour implémenter une API (la votre ou un standard reconnu du monde entier), vous devez tout d’abord créer un fichier /http/*format*.php
où « *format* » est le nom donné à votre API.
Par exemple /http/atom.php
(nous utiliserons cet exemple pour la suite).
Ensuite, vous devez créer une fonction pour chaque cas d’utilisation que vous souhaitez pouvoir gérer. Chacune de ces fonctions DOIT renvoyer l’objet Response valide, en l’ayant à priori modifié au passage, par exemple pour changer le statut de la réponse ($reponse->setStatusCode()
), ou encore son contenu ($reponse->setContent()
).
http_atom_get_index($requete, $reponse)
Vue générale d’un format, par exemple pour afficher la liste des collections disponibles.
Pour le format « atom » par exemple, il existe déjà une norme pour décrire cela. On trouve un exemple dans la documentation du standard « APP » (Atom Publishing Protocol) :
http://tools.ietf.org/html/rfc5023#section-8.2
http_atom_get_collection($requete, $reponse)
Liste le contenu de la collection dont le nom est dans la variable $requete->attributes->get('collection')
.
Pour le format « atom », ça serait un flux atom des articles (ou des résumés), par exemple.
Bien entendu, votre implémentation peut parfaitement accepter ou demander des paramètres supplémentaires, pour filtrer le contenu final. Tel que ?recherche=truc&id_rubrique=321
.
http_atom_get_ressource($requete, $reponse)
La vue d’une ressource précise (un article par exemple), dans le format attendu. L’identifiant de la ressource (l’id_article si c’en est un) est dans la variable $requete->attributes->get('ressource')
.
http_atom_post_collection($requete, $reponse)
Créer une nouvelle ressource dans la collection (créer un nouvel article). Normalement, l’utilisateur devrait avoir envoyé une représentation de la ressource dans le format géré par votre API. Par exemple un article au format atom.
Vous devez donc savoir lire ce format, et et le traiter pour créer la ressource correspondante (ajouter un article dans la base).
http_atom_put_ressource($requete, $reponse)
Ce cas est sensiblement le même que le précédent, à ceci près que l’on travaille sur la modification d’une ressource précise. Tout comme les formulaires CVT « editer_truc » savent gérer à la fois la création et la modification, il y a de grandes chances pour que ces deux dernières fonctions soient souvent similaires.
http_atom_delete_ressource($requete, $reponse)
Supprimer définitivement une ressource. Attention ce n’est pas pareil que modifier un statut (qui se ferait avec PUT à priori). Cela dépend donc des usages et des objets. Par exemple par défaut dans SPIP, on ne supprime pas un article mais on change le statut à « poubelle », et quelques temps plus tard, une tâche de fond le supprimera réellement.
Gestion générique des erreurs
Lors de l’implémentation, une fonction supplémentaire est obligatoire, pour que le plugin HTTP sache quoi renvoyer s’il trouve une erreur avant vous (avant vos fonctions précises) :
http_atom_erreur_dist($code, $requete, $reponse)
Cette fonction prend en paramètre supplémentaire un code d’erreur HTTP (401, 404, etc) et doit savoir renvoyer une réponse, si possible dans le format en rapport avec votre API.
Pour le format « atom », il n’y a malheureusement pas de syntaxe pour décrire les erreurs. Mais dans d’autres format, en JSON ou autre, il existe des manières pour lister la ou les erreurs.
Lors que le plugin HTTP rencontre une erreur d’autorisations (401) ou qu’il ne trouve pas d’implémentation pour une URL (404), il utilise cette fonction générique pour renvoyer les erreurs plus proprement.
Cela ne vous empêche pas de générer d’autres erreurs plus complexes par la suite, dans vos fonctions d’implémentation.
Gestion des autorisations
Pour chaque action demandée, le plugin HTTP teste déjà une autorisation, avec comme paramètres :
- le verbe HTTP accolé au type d’URL : « get_collection », « put_ressource », etc
- le nom de la collection si présent : « articles », « patates »
- l’identifiant de la ressource si présent : 1234
Comme on le voit, le format n’est pas présent dans le calcul de ces autorisations. En effet, on considère que si on peut faire une action (créer un article) en « atom », on peut le faire en « json » aussi, bref, quelque soit le format.
Par ailleurs, par défaut, le plugin défini déjà ces autorisations quelque soit le type de collection, en les calquant sur les fonctions déjà utilisées dans SPIP : « modifier », « creer », etc.
Dans la grande majorité des cas, vous n’aurez donc même pas à définir ces autorisations, car les utilisateurs de votre API auront tout simplement les mêmes droits que dans les interfaces de SPIP (ie : s’ils ne peuvent pas modifier tel article dans l’admin, ils ne pourront pas non plus par l’API).
Si vous devez malgré tout les préciser, l’une de vos autorisations pourrait donc ressembler à :
autoriser_article_put_ressource($faire, $quoi, $id, $qui, $opt)
Exemples
- Un exemple d’implémentation presque complet est le plugin « Collection+JSON » qui propose de manipuler les objets du site dans le format éponyme (JSON n’étant qu’un conteneur, la grammaire interne peut être n’importe quoi, ce format est une des manières de faire).
- le plugin Rest Factory simplifie encore la création d’API Rest, par la œuvre simplifiée de collections et de ressources (pour GET seulement)
- Un autre exemple, qui ne gère également que les « GET », est le plugin « APP » nommé d’après APP, Atom Publishing Protocol. Celui ci propose d’aller chercher des squelettes /http/app/patates.html
et /http/app/patates-ressource.html
correspondant respectivement au flux de la collection « patates », et à la vue d’une seule patate, dans le format Atom.
- le plugin SVP API HTTP : sur un site serveur de plugins (à l’instar de Plugins SPIP), il fournit une API REST de récupération des données d’un plugin ou d’un paquet.
Discussions par date d’activité
4 discussions
Exemple d’usage : sur le site des plugins SPIP :
- https://plugins.spip.net/http.api/svp/plugins&categorie=edition
- https://plugins.spip.net/http.api/svp/plugins/agenda
Répondre à ce message
Bonjour,
J’utilise ce plugin avec le plugin Collection+JSON. Pour les requêtes GET, pas de problème, ça marche nickel. Par contre pour les PUT/POST, je ne voie pas. C’est bloqué, ce qui normal vu que je ne suis pas authentifié, mais comment fait-on pour s’authentifier ? Je n’ai trouvé aucune doc la dessus, et l’inspection du code ne m’a rien révélé. J’ai bien vu un objet credentials.php dans collection+json, mais il a l’air de se contenter de vérifier qu’une session existe, ce qui en limiterai l’usage à quelqu’un déjà connecté à spip par les moyens "classiques.
Une idée de comment faire ?
Bé par défaut avec l’authentification HTTP que SPIP sait déjà gérer tout seul.
https://fr.wikipedia.org/wiki/Authentification_HTTP#M.C3.A9thode_.C2.AB_Basic_.C2.BB
Après on s’est déjà amusé à faire de l’auth en envoyant un token Facebook aussi, mais comme SPIP n’a pas de pipeline à cet endroit du code très en amont où SPIP gère l’auth, on a dû gérer avec le pipeline qui est au début du plugin HTTP justement, et donc c’est moyen générique car ça ne marche du coup que pour les API (ce qui est déjà pas mal ok). Du coup c’est juste dans le code du projet où on l’a utilisé pour l’instant.
L’authentification http devrai suffire. Le site est en https, ça sera « acceptable » en terme de sécurité . Merci pour la réponse rapide (et le plugin !)
Répondre à ce message
Hola Rasta ;
J’avais besoin de faire remonter une variable d’un squelette inclus jusqu’au parent,
pour qu’il puisse ensuite répercuter cette variable à un troisième squelette inclus.
Globalement c’est ça…
J’ai passé un certain temps à vouloir implémenter cette élégante solution
https://contrib.spip.net/Astuces-longues-pour-SPIP#a1
mais sans succès aucun. Pommé comme un pingouin chez le Minotaure.
Donc, est-ce que je pourrais émettre un flux provenant de Enfant A que Enfant B pourrait lire ?
Par exemple…
↓
FLUX
↑
J’ai vu que en allant à
#URL_SITE_SPIP/collectionjson/articles/1
J’ai
Où il fait la différence entre edit (l’URI)
et alternate (l’URL)
Et là je coince. Il me faudrait un exemple concret
Bah elle est très bien l’astuce du premier lien. Faire un squelette dédié qui génère un tableau (serialize ou JSON peu importe) et l’appeler avec #INCLURE pour pouvoir le mettre dans un #SET.
Je comprends le besoin expliqué au départ (et ça correspond bien à l’astuce en question), mais je ne vois pas en quoi le plugin HTTP ou le plugin Collection-JSON pourrait faire quelque chose de plus.
Pour faire quelque chose de plus, il faudrait que au moins ça arrive à marcher mal, parce que là, ça ne marche pas.
J’ai un squelette parent et deux enfants : un qui a la première boucle (qui devrait émettre) et l’autre ayant la boucle qui devrait recevoir.
Comme ça fait un moment que je bataille avec, je me suis dit que le REST était peut-être une piste. Et en plus, le plaisir d’apprendre un truc nouveau.
Je me disais qu’il me fallait un exemple de boucles pour lire,créer, modifier et détruire (et une manière de sécuriser). Mais il se peut que ce soit trop compliqué pour moi. En tout cas, ce sûr que là je ne pige pas.
Répondre à ce message
Très intéressant.
Cela ouvre des perspectives pour la mobilité...
Répondre à ce message
Ajouter un commentaire
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.
Suivre les commentaires : |