Serveur HTTP abstrait

Un plugin-outil pour aider les développeurs à implémenter des API orientées REST, basées sur les méthodes HTTP (get, post, put, delete).

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 ce format (JSON n’étant qu’un conteneur, la grammaire interne peut être n’importe quoi, ce format est une des manières de faire).
http://zone.spip.org/trac/spip-zone/browser/_plugins_/collection_json/trunk

Un autre exemple non complet, qui ne gère pour l’instant que les « GET », est le plugin « APP ». 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.
http://zone.spip.org/trac/spip-zone/browser/_plugins_/app/trunk

Discussion

Une discussion

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

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.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom