• 8 hours
  • Hard

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 11/27/23

Revenez sur l'architecture des API REST

Maintenant, vous allez construire votre API REST avec PHP et Symfony. Mais un petit instant ! Avant de se lancer tête la première dans le code, il est important de faire un petit rappel sur les règles. Eh oui, tout cela est très codifié, et pour arriver à produire une API de qualité, il faut en maîtriser tous les aspects. Commençons par le premier : l'architecture.

Rappelez-vous de l’architecture des API REST

REST n'est pas un protocole, mais une architecture. Créé par Roy Fielding en 2000, REST est un acronyme pour Representational State Transfer. Souvent associée à l'architecture orientée service (Service Oriented Architecture), cette architecture est un moyen de présenter et manipuler des ressources.

Quel est le rapport avec la notion d'architecture, alors ?

Une API (Application Programming Interface) est une application à laquelle on peut faire effectuer des actions via le protocole HTTP :

  • récupérer des données concernant des utilisateurs ;

  • ajouter des produits ;

  • supprimer l'auteur d'un article ;

  • rattacher un artiste à un spectacle…

Tout est possible !

Cela ressemble franchement à ce que nous pourrions retrouver dans un site web habituel… hormis le fait qu'il ne s'agit pas d'afficher des pages web HTML.

Les utilisateurs d'API sont d'autres développeurs (ou vous-même), et ils s'attendent à ce que votre API REST soit architecturée d'une certaine manière. C'est une bonne nouvelle !   En effet, savoir à qui vous vous adressez et comment vous devez le faire facilite grandement le travail ! Plus besoin de réfléchir à "la meilleure façon de faire". Nous ne parlons pas de code ici, mais d'une structure d'application.

Concrètement, vous aurez à créer une liste d'actions possibles avec votre application (récupérer une liste d'utilisateurs, en ajouter, en supprimer…), et une manière d'effectuer ces actions grâce à HTTP. Cette manière de faire doit respecter les nombreuses contraintes de REST.

Commençons par passer en revue ces contraintes en rapport avec ce que votre API devra refléter – les six contraintes de REST :

  • Contrainte n° 1 : Client/Server (Client-Serveur).

  • Contrainte n° 2 : Stateless (sans état).

  • Contrainte n° 3 : Cacheable (cachable).

  • Contrainte n° 4 : Layered system (système à plusieurs couches).

  • Contrainte n° 5 : Uniform interface (Interface uniforme) :

    • une ressource doit posséder un identifiant ;

    • une ressource doit avoir une représentation ;

    • une ressource doit être autodécrite.

  • Contrainte n° 6 : Code on demand (du code sur demande).

Rappelez-vous du protocole HTTP

Nous allons faire quelques rappels concernant HTTP : il s'agit d'un protocole d'échange entre deux machines. Une API n'est rien d'autre qu'une application capable de recevoir une requête HTTP et de rendre une réponse HTTP. Ce qui change d'un site web "classique" est le fait qu'il s'agit de faire des actions plus atomiques, contrairement à une page web HTML. Une API va se charger de la gestion des utilisateurs (ajout, suppression…) ou d'une gestion de produits, ou de toute autre ressource.

Revoyons ce que contiennent une requête et une réponse HTTP.

Requête HTTP

Une requête HTTP émane d'un client (tout logiciel dans la capacité de forger une requête). Une requête est constituée des éléments suivants :

  1. La première ligne (request line) doit contenir :

    - la méthode HTTP (  GET  ,   POST  ,   PUT  ,   PATCH  ,   DELETE  ,   OPTIONS  ,   CONNECT  ,   HEAD  ou   TRACE  ) ;
    - l'URI, c'est-à -dire ce qu'il y a après le nom de domaine (exemple : /users/1  ) ;
    - la version du protocole (exemple : HTTP/1.1  ).

  2. Les entêtes (headers), une entête par ligne, chaque ligne étant finie par le caractère spécial "retour à la ligne" (  CRLF  ).

  3. Le contenu de la requête (body), qui doit être séparé de deux caractères spéciaux "retour à la ligne" (  CRLF CRLF  ) – optionnel.

Voici un exemple de requête POST :

POST /users HTTP/1.1 User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
Content-Type: application/x-www-form-urlencoded Content-Length: 28 name=Sarah 
Khalil&job=auteur
Méthodes HTTP
  •  GET  : utilisée pour récupérer des informations en rapport avec l'URI ; il ne faut en aucun cas modifier ces données au cours de cette requête. Cette méthode est dite safe (sécuritaire), puisqu'elle n'affecte pas les données du serveur. Elle est aussi dite idempotent, c'est-à-dire qu'une requête faite en GET doit toujours faire la même chose (comme renvoyer une liste d'utilisateurs à chaque fois que la requête est faite – d'une requête à l'autre, on ne renverra pas des produits si le client s'attend à une liste d'utilisateurs !) ;

  •  POST  : utilisée pour créer une ressource. Les informations (texte, fichier…) pour créer la ressource sont envoyées dans le contenu de la requête. Cette méthode n'est ni safe, ni idempotent ;

  •  PUT  : utilisée pour remplacer les informations d'une ressource avec ce qui est envoyé dans le contenu de la requête. Cette méthode n'est ni safe, ni idempotent ;

  •  PATCH  : utilisée pour modifier une ressource. La différence avec une requête avec la méthode PUT est que l'action à effectuer sur la ressource est indiquée dans le contenu de la requête. Prenons un exemple : nous souhaitons rattacher un utilisateur à une organisation ; dans le contenu de la requête, il sera indiqué qu'il s'agit d'un rattachement à une organisation, en plus des informations à mettre à jour.

  •  DELETE  : utilisée pour supprimer une ou plusieurs ressources. Les ressources à supprimer sont indiquées dans l'URI.

  •  OPTIONS  : utilisée pour obtenir la liste des actions possibles pour une ressource donnée (suppression, ajout…).

  •  CONNECT  : utilisée pour établir une première connexion avec le serveur pour une URI donnée.

  •  HEAD  : même principe que pour la méthode GET, mais seuls les entêtes devront être renvoyés en réponse.

  •  TRACE  : utilisée pour connaître le chemin parcouru par la requête à travers plusieurs serveurs. En réponse, un entête  via  sera présent pour décrire tous les serveurs par lesquels la requête est passée.

Réponse HTTP

Une réponse HTTP émane d'un serveur (tout logiciel dans la capacité de forger une réponse HTTP). Une réponse est constituée des éléments suivants :

  1. La première ligne (status line) doit contenir :
    - la version du protocole utilisée ;
    - le code status ;
    - l'équivalent textuel du code status.

  2. Les entêtes (headers), un entête par ligne, chaque ligne étant finie par le caractère spécial "retour à la ligne" (  CRLF  ).

  3. Le contenu de la réponse (body) doit être séparé de deux caractères spéciaux "retour à la ligne” (  CRLFCRLF  ) – optionnel.

Voici un exemple de réponse :

HTTP/1.1 200 OK Date:Tue, 31 Jan 2017 13:18:38 GMT Content-Type: application/json {
 "current status" : "Everything is ok!" }
Code status

Il est important d'accorder une attention toute particulière aux codes status qui doivent être choisis avec sagesse lorsqu'il vous faudra rendre une réponse. Il existe cinq catégories de codes status, les voici :

Catégorie

Description

1xx : les informations

Une réponse doit contenir ce type de code status lorsqu'il s'agit d'informer le client de l'état de la demande. C'est utile pour indiquer que, par exemple, la requête a bien été reçue et que le traitement vient de commencer, dans le cas de traitements asynchrones, notamment.

2xx : les succès

Tout s'est bien passé sur le serveur.

3xx : les redirections

Une redirection est sur le point d'être effectuée.

4xx : les erreurs client

La requête contient une erreur et ne peut pas être traitée.

5xx : les erreurs serveur

Le serveur vient de rencontrer un problème empêchant le traitement de la requête.

Voyons maintenant comment une application REST devient RESTful, c'est à dire pleinement REST.

Découvrez le modèle de maturité de Richardson

Le modèle de Richardson est aussi connu que la reine d'Angleterre, toutes proportions gardées, dans le monde des API REST.  Ce modèle donne un moyen d'évaluer son API. Plus on monte dans les niveaux, plus notre API est considérée RESTful (pleinement REST, autrement dit). Plus votre API adhère aux contraintes REST, plus elle est RESTful, ce qui est plutôt bien du point de vue des bonnes pratiques : en effet, étant donné que rien n'est imposé, le fait de respecter les règles permet de faire en sorte que ceux qui connaissent et aiment utiliser les API REST, et/ou développer des API REST, adopteront plus facilement votre travail.

Passons en revue ce modèle ensemble. Il existe 4 niveaux, de 0 à 3 :

Les 4 niveaux : 0, Marécage du Plain Old XML ; 1, Ressources ; 2, Méthodes HTTP ; 3, Contrôles hypermédia.
Niveaux de respect du modèle de maturité de Richardson

Je vous invite à lire les explications en anglais de Martin Fowler (Steps toward the glory of REST). Je vous propose tout de même une explication de chacun des niveaux dans la suite de ce cours.

Level 0 : The Swamp of POX (le marécage du Plain Old XML)

Une API qui ne fait que respecter le niveau 0 n'est pas une API REST. Ce niveau ressemble plus à ce que l'on peut retrouver dans une API SOAP (type d'API plutôt old school).

Il s'agit de :

  • n'utiliser qu'un seul point d'entrée pour communiquer avec l'API, c'est-à-dire une seule URI, comme par exemple  /api  ;

  • n'utiliser qu'une seule méthode HTTP pour effectuer ses demandes à l'API, avec POST.

Ces deux règles ne sont pas à suivre selon les contraintes de REST énoncées : en effet, chaque ressource devrait avoir son point d'entrée. Si par exemple notre API gère des utilisateurs et des produits, il devrait y avoir au moins deux URI différentes pour récupérer ces listes,  /users  et  /products  . Par ailleurs, l'utilisation de la méthode HTTP   POST  pour toutes les actions que nous souhaitons effectuer sur l'API n'est vraiment pas une bonne idée : comme expliqué plus haut, la méthode  POST  n'est réservée qu'à la création de ressources. Si nous souhaitons récupérer une liste d'utilisateurs, il faudra utiliser la méthode   GET  pour la requête.

Du coup, ce niveau 0 n'a rien de bon à priori. Passons au suivant.

Level 1 : Les ressources

Le niveau 1 concerne les ressources et demande dans un premier temps que chaque ressource puisse être distinguée séparément. Cela ne vous rappelle rien ? Mais si, la contrainte n° 5 ! Je ne vais pas me répéter, du coup.  Simplement, rappelez-vous qu'il faut que vos URI correspondent à la ressource que le client de votre API souhaite manipuler.

J'ajouterai encore un petit quelque chose, en prenant un exemple concret : une API permettant de manipuler des articles. Disons que nous souhaitons développer un CRUD (CRUD est un acronyme anglais pour Create, Read, Update et Delete, soit Créer, Lire, Mettre à jour et Supprimer). La première question qu'il faut se poser est la suivante :

Quelles vont être les URI par lesquelles les utilisateurs de mon API vont pouvoir effectuer ces actions ?

Nous devons réfléchir aux points d'entrée dès le début. D'après ce que dit le niveau 1 du modèle de Richardson, les solutions possibles devraient être :

  • pour la création d'articles,  /articles/create  ;

  • pour la lecture d'articles, nous aurions  /articles  (liste des articles) et  /articles/{identifiant-unique}  (un seul article) ;

  • pour la mise à jour/articles/{identifiant-unique}/update  ;

  • et enfin, pour la suppression, ce serait plutôt  /articles/{identifiant-unique}/delete  .

Le niveau 1 ne prévoit pas de faire usage des différentes méthodes HTTP. Toutes les requêtes se font en  POST  ici. C'est dommage ! 

Mais, bonne nouvelle, le niveau 2 vient à la rescousse pour pallier ce problème ! 

Level 2 : Méthodes HTTP

Nous ajoutons maintenant l'utilisation des méthodes HTTP en fonction de l'action qu'il faut effectuer sur l'API. Reprenons donc notre exemple d'API permettant un CRUD sur des articles. Il va falloir changer un peu les URI et se servir des méthodes HTTP pour indiquer nos intentions. Voyons comment nos requêtes devront être formulées :

  • Création :  POST  /articles   ;

  • Lecture : GET /articles  ou  GET /articles/{identifiant-unique}  ;

  • Mise à jour :  PUT /articles/{identifiant-unique}  ;

  • Suppression :  DELETE /articles/{identifiant-unique}   .

Comme vous pouvez le voir, les actions ne font plus partie de l'URI. C'est primordial de les retirer. L'information concernant l'action est désormais contenue dans la méthode HTTP. Nous utilisons la pleine capacité du protocole HTTP !

Autre point abordé par le niveau 2 : le code status. Si vous décidez de respecter le niveau 2 du modèle de Richardson, il faut choisir avec sagesse le code retour HTTP dans vos réponses. Voici un petit tour des codes status les plus courants que vous serez amené à retourner en fonction des situations :

  • 200 OK – Tout s'est bien passé ;

  • 201 Created – La création de la ressource s'est bien passée (en général le contenu de la nouvelle ressource est aussi renvoyé dans la réponse, mais ce n'est pas obligatoire – on ajoute aussi un header Location avec l'URL de la nouvelle ressource) ;

  • 204 No content – Même principe que pour la 201, sauf que cette fois-ci, le contenu de la ressource nouvellement créée ou modifiée n'est pas renvoyé en réponse. Ce code de retour est également utilisé lorsqu’on vient juste de supprimer une ressource ;

  • 304 Not modified – Le contenu n'a pas été modifié depuis la dernière fois qu'il a été mis en cache ;

  • 400 Bad request – La demande n'a pas pu être traitée correctement ;

  • 401 Unauthorized – L'authentification a échoué ;

  • 403 Forbidden – L'accès à cette ressource n'est pas autorisé ;

  • 404 Not found – La ressource n'existe pas ;

  • 405 Method not allowed – La méthode HTTP utilisée n'est pas traitable par l'API ;

  • 406 Not acceptable – Le serveur n'est pas en mesure de répondre aux attentes des entêtes   Accept . En clair, le client demande un format (XML, par exemple) et l'API n'est pas prévue pour générer du XML ;

  • 500 Server error – Le serveur a rencontré un problème.

Retenez simplement que plus vous serez explicite dans la réponse générée, meilleure sera la qualité de votre API.

Level 3 : Contrôles hypermédia

Et enfin le niveau 3, The glory of REST ! Le niveau 3 est simplement l'idée de rendre votre API autodécouvrable, en imitant les liens hypertextes d’une page web classique. Concrètement, nous devons indiquer au client de votre API ce qu'il est possible de faire à partir d'une ressource.

Reprenons l'exemple de l'API de gestion d'articles : si le client demande un article, non seulement il obtiendra les informations de l'article en question (titre, contenu…), mais aussi la liste des liens (URL) pour effectuer d'autres actions sur cette ressource, comme la mettre à jour, ou voir un article associé, par exemple.

Voici un exemple de contenu de réponse offrant une autodécouverte de l'API :

{
   "id" : 1,
   "title" : "Le titre de l'article",
   "content" : "<p> Le contenu de l'article.</p>",
   "links" : {
      "update" : "http://domain.name/article/1",
      "associated" : "http://domain.name/article/16"
   }
}

Bien évidemment, d'autres développeurs se sont intéressés à la question et ont proposé plusieurs solutions pour présenter ces liens. Nous aborderons le sujet plus en détail plus tard dans ce cours, et cela promet d'être une (auto)découverte ! 

En résumé

  • Une API est une application capable de recevoir une requête HTTP avec des méthodes HTTP, et de rendre une réponse HTTP avec un code status.

  • Vous pouvez évaluer une API avec le modèle de maturité de Richardson, constitué de 4 niveaux :

    • niveau 0 : marécage du Plain Old XML ;

    • niveau 1 : les ressources ;

    • niveau 2 : méthodes HTTP ;

    • niveau 3 : contrôles hypermédia.

Nous en avons fini avec ce premier chapitre d'introduction à REST. Dès le prochain chapitre, nous commencerons à mettre en place l’environnement pour créer une API REST avec Symfony !

Example of certificate of achievement
Example of certificate of achievement