Nous vivons aujourd'hui dans un monde où tout devient service. Twitter, Facebook, Google Drive, GitHub, tout le monde y va de sa petite API pour que nous, geeks, puissions profiter pleinement des moult fonctionnalités offertes par ces plateformes. Qu'entend-on par service ? Comment les rendre disponibles facilement et intelligemment ? On va essayer d'y répondre !
Rappelons juste, pour mettre tout le monde d'accord, ce qui se passe pendant une simple navigation web.
On parle donc de contenu qu'il faut afficher pour les êtres humains, avec des images, des styles et des comportements qui facilitent l'ergonomie et te permettent de dire "wouaouw, ce site est vraiment beau, cool et pratique !"
Imaginons maintenant la même chose, mais à destination des programmes, qui ne consomment que de l'information brute et structurée, on ne va donc plus s'encombrer avec les CSS, les JS, et autres gifs animés (oui, les gifs animés, ça les fait pas marrer les machines...) ! On va se concentrer sur le contenu échangé et sur les moyens utilisés pour optimiser ces échanges.
Imaginons deux programmes qui veulent discuter en passant par le web. Dans les années 90, des gens super brillants se sont dit : "On va se baser sur le XML pour faire communiquer nos programmes sur le web". L'approche est assez logique et ingénieuse. Tout d'abord, les deux parties (le client et le serveur) se partagent une notice d'utilisation : la WSDL (Web Service Description Language), qui est un document XML décrivant toutes les méthodes qui peuvent être appelées par le client sur le serveur, avec les structures de données disponibles pour ces échanges. Le client prépare donc sa demande et l'enveloppe dans une grosse structure XML contenant toutes les métadonnées (méthode appelée, signature numérique, etc.). Une fois que le serveur a reçu cette demande, il la traite et répond aussi dans une grosse enveloppe XML.
Tu viens de comprendre le SOAP (Service Oriented Application Protocol), aucun rapport avec une quelconque savonnette du coup. Cette méthode a fait ses preuves puisqu'elle fait tourner encore aujourd'hui des milliers de systèmes très complexes et très fiables.
Plusieurs années ont passées et les esprits ont évolué. On a commencé à entendre des grandes déclarations comme : "Le SOAP c'est vraiment lourdingue !", "Le protocole HTTP est sous-exploité !" ou encore "Les enveloppes XML et les WSDL ? Merci bien !" et c'est à ce moment-là qu'on a donné un acronyme bidon pour décrire le protocole HTTP sans vraiment le nommer : REST (REpresentational State Transfert). Pour l'anecdote, tout le monde s'accorde à dire que cet acronyme ne veut rien dire ;)
Le but du jeu est donc d'utiliser au maximum les possibilités du protocole HTTP, les verbes, les URL et les codes retours pour décrire des API de la manière la plus fidèle possible. On a donc gagné en simplicité et la communication entre machines se veut désormais à la portée de tous. Je reviendrai en détail sur le protocole HTTP un peu plus tard.
Je tiens à remettre les choses au clair. On entend beaucoup trop souvent : "Fais du REST, SOAP c'est nul". Il y a en effet clairement un effet de mode ! Les API REST pullulent et sont vraiment très pratiques. Toutefois, dans les gros systèmes nécessitant du RPC ou encore de la signature numérique, pour les échanges de données médicales par exemple, le contrat WSDL et la rigueur du XML sont clairement des alliés !
Il y a un type qui s'appelle Leonard Richardson et qui a mis en place un modèle de maturité pour qualifier les API webservice.
C'est le minimum acceptable dans la communication HTTP :
Quand on fait du webservice avec SOAP, c'est ce niveau qui est utilisé lors de la communication HTTP.
Avec ce premier niveau, on essaye d'enrichir un peu plus l'utilisation. On ajoute la notion de ressource, en fonction de la donnée métier manipulée, l'URL de la requête sera différente. La preuve par l'exemple :
On profite aussi de la vue hiérarchique que nous proposent les URL :
Rien qu'en traçant les URL appelées sur le serveur, on peut comprendre ce que le client HTTP cherche à faire... pas dégueu, non ?
Le protocole HTTP utilise des verbes pour les requêtes et des codes numériques pour les retours. Ce sont ces deux mécanismes qui seront utilisés en complément du niveau 1.
Les principaux verbes HTTP que l'on utilise sont GET, POST, PUT et DELETE. Leur nom est déjà très évocateur.
Facile, non ? La réponse du serveur devient tout aussi logique grâce aux codes HTTP. Ces codes sont juste des nombres de 3 chiffres respectant cette logique :
Parmi les plus connus, on a donc 404 ("tu me demandes quelque chose qui n'existe pas"), 403 ("accès interdit"), 304 ("pas la peine de m'emmerder, la donnée est dans ton cache") et bien sûr 200 ("OK, tout va bien").
Et si les codes HTTP sont ta nouvelle passion, je te suggère de te documenter sur le code 418 !
Alors on a les verbes HTTP et les codes retours. À quoi peut ressembler le Graal des API REST alors ? Si on réfléchit un peu, on peut se dire qu'il faudrait, pour toutes les URL, donner un code retour HTTP cohérent pour chaque verbe, logique non ? De cette manière, on peut entamer un véritable dialogue avec le serveur HTTP, entièrement basé sur REST. Voilà une bonne nouvelle pour ceux qui veulent tailler une bavette ailleurs que sur Google Hangouts !
Un petit exemple de dialogue :
> GET /customers/42
200 OK
> PUT /customers/42 {...}
409 Conflict
> DELETE /customers/42
204 No Content
> GET /customers/42
404 Not Found
C'est un bon début, mais ce niveau 3 va quand même un peu plus loin ! N'as-tu jamais trouvé génial qu'avec de simples liens dans les pages web, tu pouvais naviguer des heures et des heures ?
Pourquoi ne pas ajouter des liens dans les ressources retournées via REST ? Nous venons de mettre le doigt sur HATEOAS (Hypermedia As The Engine Of Application State). On peut désormais imaginer un tas de choses comme :
Voici un exemple de trame JSON avec les informations HATEOAS. Pour information, il s'agit d'un webservice qui permet de lister des conférences.
[
{
"conference": {
"id": 1,
"links": [
{
"rel": "list",
"href": "http://localhost:8080/hateoas-webservice/rs/conferences/"
},
{
"rel": "self",
"href": "http://localhost:8080/hateoas-webservice/rs/conferences/1"
}
],
"name": "Take Off Conf 2013",
"startDate": "2013-01-17T00:00:00+01:00",
"endDate": "2013-01-18T00:00:00+01:00",
"talks": [
{
"id": 1,
"speakerName": "Jakob Mattsson",
"title": "You are not service oriented enough!",
"links": [
{
"rel": "self",
"href": "http://localhost:8080/hateoas-webservice/rs/talks/1"
},
{
"rel": "list",
"href": "http://localhost:8080/hateoas-webservice/rs/talks/"
}
]
},
{
"id": 2,
"speakerName": "Olivier Lacan",
"title": "Science-based development",
"links": [
{
"rel": "self",
"href": "http://localhost:8080/hateoas-webservice/rs/talks/2"
},
{
"rel": "list",
"href": "http://localhost:8080/hateoas-webservice/rs/talks/"
}
]
},
{
"id": 3,
"speakerName": "Xavier Coulon",
"title": "Build your website with awestruct and publish...",
"links": [
{
"rel": "self",
"href": "http://localhost:8080/hateoas-webservice/rs/talks/3"
},
{
"rel": "list",
"href": "http://localhost:8080/hateoas-webservice/rs/talks/"
}
]
},
{
"id": 4,
"speakerName": "Rémi Parmentier",
"title": "Design for developers",
"links": [
{
"rel": "self",
"href": "http://localhost:8080/hateoas-webservice/rs/talks/4"
},
{
"rel": "list",
"href": "http://localhost:8080/hateoas-webservice/rs/talks/"
}
]
}
]
}
},{
...
}
]
Dans cette trame, tu auras remarqué les objets dans les tableaux nommés "links", ce sont les liens disponibles pour chacun des objets renvoyés ! On peut imaginer qu'en fonction des droits de l'utilisateur courant, il y ait plus ou moins de liens.
Eh bien non ! Il n'y a pas vraiment de convention pour l'écriture des liens dans les trames renvoyées. Cela dépend du format renvoyé dans un premier temps. Comment formaliser un standard si on renvoie en JSON, XML et YML en fonction des en-têtes HTTP du client ?
De la même manière, tu auras remarqué que l'on ne précise pas le verbe HTTP à utiliser sur les URL. C'est la raison pour laquelle il faut implémenter un retour cohérent pour tous les verbes HTTP courants !
Et pour finir, comment connaître le format du document JSON accepté avec les requêtes POST par exemple ? Il n'y a pas non plus de règle ! On pourrait imaginer par exemple un document "type" qui serait renvoyé après une requête "OPTION" sur l'URL.
Il y a toutefois quelques expérimentations comme HAL ou encore JSON API qui tentent de normaliser un peu ce flou artistique.
Tu fais ta petite popote ! Tu fais comme tu veux ! Ça a du bon aussi !
Tu remontes tes manches et tu te démerdes !
Il y a quelques frameworks qui vont te donner un coup de main. Dans le monde Java par exemple, il existe Resteasy-links (avec un exemple d'utilisation sur mon repo GitHub), ou encore Spring HATEOAS
Pour les Nodistes, une simple recherche sur npmjs renverra un tas d'outils !
Oui, parce qu'il y a des gens bien plus brillants que moi pour vous convaincre sur l'Hypermedia !