Qu'est-ce qu'une API REST ?
Comment fonctionne une API REST ? Quelles sont les contraintes ? Est-ce compatible avec tous les projets ? C'est ce que nous allons découvrir ensemble !
Article publié le 30/05/2022, dernière mise à jour le 19/09/2023
Commençons par rappeler ce qu'est une API : une "Application Programming Interface" est un ensemble de fonctionnalités disponibles au travers d'une couche d'abstraction simplifiée et permettant de développer un logiciel grâce à la "consommation" de cette dernière.
Si vous voulez en savoir plus sur les APIs, notre article API vs SDK est toujours en ligne !
Cette définition est valable pour les APIs REST, GraphQL, SOAP, etc... Mais qu'est-ce qui différencie une API Rest des autres ?
C'est ce que nous allons voir ensemble !
Les caractéristiques d'une API Rest
Conçu pour le web
Certaines API sont mises à disposition par le système d'exploitation, par le navigateur, et d'autres par des serveurs disponibles sur Internet.
Le concept de REST est basé sur le protocole HTTP, il est donc indissociable d'Internet, et plus précisément du web.
Bien sûr une API REST peut être consommée depuis n'importe quel système ou langage, le seul prérequis est la possibilité d'effectuer des requêtes HTTP
État vs Transactions
Pour commencer, il faut savoir que "REST" signifie "Representational State Transfer", et cette définition n'est pas vide de sens.
Certaines APIs (SOAP et GraphQL par exemple) proposent une abstraction basée sur des transactions, comme ceci :
- listArticle()
- createOrUpdateArticle(data)
- deleteArticle(Id)
Ici le terme transaction est un synonyme d'un ensemble d'opérations, de fonctions exécutées dans un certain ordre
Alors que REST est basé sur la représentation directe des données. Au lieu d'exposer les transactions disponibles, elle expose des ressources sous la forme d'URL afin de représenter l'état des données.
Exemple :
- GET /articles (Retourne tous les articles)
- GET /articles/1 (Retourne les détails de l'article 1)
- POST /articles (Créé un nouvel article et le retourne)
- PUT /articles/1 (Modifie l'article 1 et retourne l'article modifié)
- DELETE /articles/1 (Supprime l'article 1)
Ici on peut voir que chaque appel n'affectera que la ressource en question, et que chaque méthode pour mettre à jour une ressource est indépendante.
Par exemple pour recréer le même comportement que la transaction précédente createOrUpdateArticle(data) , alors il faudra un appel GET, puis un appel POST ou PUT.
Voilà pourquoi on parle de représentation des données, et non pas de transactions pour une API REST.
Les règles d'une API RESTful
Si l'on résume le concept d'API REST, c'est une API qui permet de récupérer et modifier des ressources grâce à des appels et des méthodes HTTP.
Mais pour aller plus loin et concevoir une API RESTful normalisée, il existe 6 règles à respecter.
Si et seulement si ces contraintes architecturales sont respectées, on parlera alors d'API RESTful. Voici les 6 contraintes à respecter pour concevoir une API dans les règles de l'art :
1 - Interface uniforme
Une interface uniforme signifie que chaque appel à l'API aura la même forme, que chaque type d'appel doit avoir le même comportement et que chaque réponse sera formulée de la même manière.
Cette uniformisation porte principalement sur la manière dont chaque ressource est ciblée, comment les données sont transmises et quelles opérations leurs sont appliquées.
Voici les points importants à respecter :
1.1 - URI = Ressource
La partie la plus importante d'une requête, c'est la ressource, elle est représentée par l'URI (Unique Ressource Identifier) et peut contenir des paramètres pour spécifier une ressource précise.
Exemple :
- /houses => La liste de toutes les maisons
- /houses/1 => Les détails de la maison n°1
- /houses/1/rooms => La liste des pièces de la maison 1
- /houses/1/rooms/1 => Les détails de la première pièce de la maison n°1
1.2 - Méthode HTTP = Action
Ensuite, pour agir sur une ressource, on va exploiter les méthodes HTTP, de la manière suivante :
- GET pour lister, récupérer une ou plusieurs ressources
- POST pour créer une ressource
- PUT pour mettre à jour une ressource
- DELETE pour supprimer une ressource
La bonne conception d'une API RESTful réside notamment dans le respect des règles sémantique d'HTTP comme l'idempotence
1.3 - Corps de la requête = Données
Les données (parfois appelées payload) seront passées dans le corps de la requête pour les méthodes HTTP le permettant, en l'occurrence les requêtes POST et PUT.
Il n'y a pas de limitation sur le format des données passées à l'API, on utilise souvent le format JSON, mais on peut trouver des API acceptant le format XML, BLOB, etc..
Certaines API acceptent et acceptent/renvoient même plusieurs types différents, en rapport avec les informations contenues dans les en-têtes "Accept" et "Content-Type".
1.4 - En-têtes = Métadonnées
Toutes les informations supplémentaires requises par l'API pour son bon fonctionnement, comme :
- Les données d'authentification
- La langue
...seront communiquées par les en-têtes des requêtes comme par exemple "Authorization", "Accept-Language", etc...
1.5 - Code de status = Résultat
Le résultat des opérations effectuées par l'API devra toujours être représenté par le code de status HTTP correspondant, toujours en gardant en tête que la sémantique de l'API doit être le plus explicite possible.
Quelques examples de code de retours les plus courants :
- 200 => Succès
- 201 => Succès, une nouvelle ressource a été créée
- 404 => Ressource introuvable
- 400 => Problème dans la requête
L'un des exemple à éviter est par exemple le renvoi d'un code 200, avec un message "Error: xxxx" dans le corps de la requête.
Si vous voulez en apprendre plus sur les codes de status HTTP à connaitre absolument, voici un article dédié.
1.6 - HATEOAS
HATEOAS signifie (Hypermedia As The Engine Of Application State), et derrière cet acronyme ce cache en réalité un concept assez simple.
Une API RESTful n'est pas seulement censée fournir les données d'une ressource, mais également les liens (hypertextes) directs vers les ressources connexes dans le but de rendre le parcours de ressources plus simple, et automatisable.
Exemple, un appel [GET api.example.com/articles/1] vous donnera les détails d'un article de blog avec notamment le nom de l'auteur, mais la réponse contiendra également un lien vers "api.example.com/author/2637" dans l'objet de l'auteur !
2 - Client-Serveur
Cette contrainte parait évidente lorsque l'on compare une API RESTful à du GraphQL par exemple, mais comme expliqué au début de l'article, il y a beaucoup d'APIs mises à diposition par le système, et non au travers d'un serveur distant.
Une API REST, elle, fonctionne selon une architecture client-serveur obligatoirement !
3 - Sans-état (Stateless)
La contrainte "sans-état" décris un mode de fonctionnement dans lequel aucune information n'est conservée sur le serveur entre deux appels consécutifs.
L'exemple le plus parlant reste celui de l'authentification : en utilisant un système de sessions stockées sur le serveur, alors ce dernier conserve un état en mémoire, on parle alors d'un fonctionnement "stateful".
Une API "stateless" va plutôt utiliser une authentification par token (par exemple), et les informations de l'utilisateur seront stockées dans une base de données et récupérées à chaque nouvel appel, grâce au jeton fourni dans chaque requête.
Cela permet notamment de déployer son API sur plusieurs machines, pour passer à l'échelle (scaling) de manière horizontale, sans risquer de perdre l'état actuel d'une machine, et donc l'authentification d'un utilisateur.
4 - Mise en cache
Contrairement à certains autres types d'API où le cache n'est pas la priorité, les appels de lecture (GET) d'une API RESTful doivent pouvoir être mis en cache afin d'optimiser les performances au niveau de la récupération de données.
5 - Système à plusieurs niveaux
Cette contrainte ne signifie pas que votre API se DOIT de contenir plusieurs niveaux, mais PEUT contenir plusieurs niveaux.
Par exemple on peut imaginer que votre serveur d'API tourne derrière un certain nombre d'autres serveurs, comme un serveur de cache, un (reverse)proxy, un répartiteur de charge, etc...
La contrainte ici est que les requêtes et les réponses de votre API REST ne doivent pas être impactée par ces intermédiaires, cela doit être absolument transparent pour le client qui envoit et reçoit ces requêtes.
6 - Code à la demande (optionnel)
La contrainte de "Code-on-demand" est la seule qui est optionnelle, d'abord parce que ça ne répond pas aux besoins de tous les projets, et car il peut y avoir quelques implications en terme de sécurité.
En théorie, un client est capable de demander du code à une API RESTful, qui sera alors contenu dans le corps de la réponse, pour être exécuté sur le client.
Par exemple, on peut imaginer une balise script récupérée et contenant une méthode de calcul spécifique pour une donnée, utilisée par le front-end d'une application.
Aucun commentaire pour l'instant