Les fondamentaux d'une API REST

  • Date
  • Auteur
    Pascal Lecatelier

Les APIs vous offre la possibilité de bénéficier de services tiers qui ajoutent de la valeur à votre système d'information sans devoir les développer vous-mêmes. Elles vous permettent également d'échanger des données avec vos clients, vos partenaires et vos fournisseurs en ouvrant votre système d'information afin de simplifier et monétiser vos services.

L'avantage qu'apportent les APIs dans votre transformation digitale repose sur un respect de fondamentaux de conception afin de veiller que vos APIs soient simples à utiliser, fiables, sécurisées et maintenables.

KISS : « Keep it simple, stupid »

Un des objectifs d’une stratégie API vise à “s’ouvrir” et donc à toucher un large public de développeurs. Il est donc indispensable que l’API soit la plus simple possible et auto-descriptive. On parle également d’affordance : c’est à dire la capacité pour l’API d'être auto-suggestive.

L'API est “désignéepour le client : les développeurs. Elle ne doit pas être l’exposition des données de l’entreprise. L’API doit proposer des fonctionnalités simples qui répondent aux besoins du client.

Pour beaucoup d'entre nous, la conception d'une API REST peut parfois ressembler d'avantage à un art qu'à une science.
Mark Massé Rest API Design RuleBook.

Client / Serveur

L’architecture REST repose sur les principes historiques du Web : un client interagit de manière transparente avec un serveur via un protocole sans état et l’architecture applicative, elle repose sur le principe du Client / Server afin de répartir et de :
•    simplifier l’implémentation des fonctionnalités “Core Business” Métier, coté serveur,
•    rendre les requêtes cachables, si la réponse est toujours la même pour une même question,
•    gagner en résilience et en scalabilité :
        - plus de “session utilisateur” consommatrice de mémoire coté serveur,
        - plus de “sticky session” au niveau du loadbalancer,
        - pas de problématique de réplication de session entre noeuds applicatifs impactant la complexité, la robustesse et la performance globale de l’architecture.

Stateless

Stateless signifie que l'API ne doit conserver aucun contexte entre deux appels successifs, et ne dépend que de l’état des ressources au moment de l’appel.

Il ne s’agit pas de s’affranchir de toute gestion de contexte, mais de séparer les responsabilités :
•    Le client est responsable de l’état de l’application :
        - navigation,
        - session utilisateur authentifiée,
        - enrichissement de l’expérience utilisateur.
•    Le serveur est responsable de l’état de ses ressources :
        - persistance,
        - cohérence,
        - transitions entre états.

Uniform interface

La méthode de communication entre client et serveur doit être uniforme avec des ressources identifiables, représentables et autodescriptives. C'est à dire avec une URL et une réponse contenant un body et une entête.

Hypermedia-driven

Le Hypermedia-driven correspond au niveau 3 du modèle de maturité des API de Richarson :
•    Niveau 0 - Protocole d'échange HTTP, le principe : envoi d’une requête et attente d’une réponse,
•    Niveau 1 - Introduction d’une notion de ressource au sein de l’API,
•    Niveau 2 - Emploie des verbes HTTP et code retour : chaque verbe et chaque code retour ayant une signification.
•    Niveau 3 - Documentation interactive des ressources selon les appels effectués.

HATEOAS (Hypermedia As The Engine of Application State) est un concept de lien au sein d’une API avec ajout des liens hypermédias dynamiques dans les réponses. A l’aide de ces liens, il est possible de naviguer dans une API comme sur un site web. L’importance de l’Hypermédia est de rendre une API découvrable et navigable de façon autonome, rendant l'API plus flexible dans la mesure où le client sera en capacité, à partir d’un lien unique, de naviguer dans toutes les APIs.

Une ressource est tout ce qui est assez important
pour être référencé comme une chose en soi.
Leonard Richardson, RestFul WebApi

Ressources et représentations


Le diagramme de maturité du REST de Leonard Richardson

Niveau 0

Vous utilisez le protocole HTTP les services REST ont une seul URI et utilisent une seule méthode HTTP. Il s'agit de la manière la plus basique de créer des applications SOA avec une seule méthode POST et un format d’échange en XML pour communiquer entre les services. Tout l'échange est défini par le format XML dans le cas des services Web SOAP, appelé POX (Plain Old XML).

Exemple:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://www.mymeteo.com/meteo">
<soapenv:Header>
</soapenv:Header>
    <soapenv:Body>
     <m:releve>
       <m:temperature>
         <m:valeur>6.0</m:valeur>
         <m:unite>celsius</m:unite>
       </m:temperature>
       <m:lieu>
         <m:ville>Bordeaux</m:ville>
       </m:lieu>
     </m:releve>
   </soapenv:Body>
</soapenv:Envelope>

Niveau 1

Les «ressources» REST sont les données de base sur lesquelles votre application agit. Elles correspondent souvent aux modèles de votre application. (Implémentation couramment utilisée : MVC). La conception d’une API au niveau 1 consiste à utiliser des URL distinctes pour interagir avec les différentes ressources de votre application.

Exemple : Articles est une API qui gère un catalogue d'articles, voici son implémentation pour le niveau 1:

Exemple:

/ addNewArticle
/ updateArticle
/ deleteArticle
/ deleteAllArticle
/ promouvoirArticle
/ promouvoirAllArticle

Dans l’exemple de niveau 1, il existe un ensemble d'opérations communes qui sont effectuées sur les ressources et il donc inutile de créer une nouvelle URI pour chacune d’entre elles. Le niveau 2 quant à lui optimises l’organisation de ces opérations.

Niveau 2

L’ensemble des opérations effectuées sur les ressources repose sur les 4 opérations de base : CRUD (Create, Read, Update, Delete). L’utilisation de verbes HTTP permet de faire correspondre chaque opération de base avec un verbe HTTP :

Méthode Périmétre Description CRUD
GET Collection Retrouve toutes les ressources d'une collection. R
GET Ressource Retrouve une ressource unique. R
HEAD Collection Retrouve toutes les ressources d’une collection depuis l’entête http uniquement. R
HEAD Ressource Retrouve une ressource unique depuis l’entête http uniquement. R
POST Collection Créée une nouvelle ressource dans une collection. C
PUT Ressource Met à jour une ressource. U
PATCH Ressource Met à jour une partie de la ressource. U
DELETE Ressource Supprime une ressource. D
OPTIONS Tous Retourne les méthodes HTTP disponibles et les autres options. -
POST (surchargé) Ressource Exécution pour toutes les fonctionnalités ne correspondant pas aux méthodes CRUD précédentes. -

Niveau 2.1

Les entêtes HTTP fournissent également les informations requises sur la demande, la réponse ou sur l'objet envoyé dans le corps du message. Il existe 4 types d'en-têtes de message HTTP :
•    En-tête général : Ces champs d'en-tête ont une applicabilité générale pour les messages de demande et de réponse,
•    En-tête de demande client : Ces champs d'en-tête sont applicables uniquement aux messages de demande,
•    En-tête de réponse du serveur : Ces champs d'en-tête sont applicables uniquement aux messages de réponse,
•    En-tête d'entité : Ces champs d'en-tête définissent des méta-informations sur l'entité-corps ou, si aucun BODY n'est présent, sur la ressource identifiée par la demande.


Niveau 2.2

Une partie importante de la conception d’une l'API REST est l'utilisation des paramètres de requête ; Ils sont principalement utilisés dans les cas suivant :
•    Pagination : Il est nécessaire d'anticiper la pagination des ressources dans la première phase de conception de l'API,
•    Filtrage : Le filtrage consiste à restreindre le nombre de ressources interrogées en spécifiant certains attributs et leurs valeurs attendues. Il est possible de filtrer une collection sur plusieurs attributs en même temps et d'autoriser plusieurs valeurs pour un attribut filtré,
•    Tri : Le tri du résultat d'une requête sur une collection de ressources. Un paramètre de tri doit contenir les noms des attributs sur lesquels le tri est effectué, séparés par une virgule,
•    Recherche : Une recherche est une sous-ressource d'une collection. À ce titre, ses résultats auront un format différent de celui des ressources et de la collection elle-même.


Niveau 2.3

Il est important de normaliser dans une API RESTful des codes d'état HTTP appropriés :

Exemple:

/ articles
/ articles/all

Exemple : Articles d'une API qui gère un catalogue d'articles, voici son implémentation pour le niveau 2. On combinera les 2 ressources avec les verbes GET, POST, PUT, ou DELETE.


Niveau 3

Ce niveau recouvre deux parties distinctes :
•    La négociation de contenu : elle se concentre sur différentes représentations d'une ressource particulière,
•    HATEOAS : concerne la découverte des actions sur une ressource.


Niveau 3.1

Généralement, les ressources peuvent avoir plusieurs présentations principalement parce que plusieurs clients différents peuvent attendre des représentations différentes. Demander une présentation appropriée par un client est appelé “négociation de contenu”.

HTTP inclut plusieurs mécanismes de «négociation de contenu» - le processus de sélection de la meilleure représentation pour une réponse donnée lorsque plusieurs représentations sont disponibles.

La correspondance de la représentation spécifiée par le client s’effectue via l'en-tête Accept avec la représentation que l’API peut fournir. La négociation de contenu consiste à préciser de la part du client ce qu'il envoie et ce qu'il souhaite recevoir, et au serveur de déterminer s'il peut traiter la demande du client, par exemple :GET / foo HTTP / 1.1Accepter: application / json

Ce qui précède indique que le client veut une réponse au format JSON. Il appartient désormais au serveur de déterminer s'il peut renvoyer cette représentation.

Si le serveur ne peut pas renvoyer un format JSON, il doit en informer le client avec le code d'état HTTP 406;

Comme le serveur ne peut pas renvoyer une représentation pour le type de média demandé, il peut choisir le type de média qu'il souhaite pour la réponse afin de communiquer les erreurs.

Si le serveur peut renvoyer le type de média demandé, il doit signaler le type de média via l'en-tête Content-Type de réponse.

Une même URI peut répondre avec plusieurs types de média et obtenir plusieurs représentations de la même ressource : text / htm ou application / json ou application / xml

Le deuxième aspect de la négociation de contenu consiste à identifier l'en-tête de type de contenu entrant et à déterminer si le serveur peut désérialiser ces données.


Par exemple, le client peut envoyer les éléments suivants : POST / foo HTTP / 1.1Accepter: application / jsonType de contenu: application / json{ "foo": "bar"}

Le serveur introspecterait l'en-tête Content-Type et déterminerait que le format JSON a été soumis. Il devrait maintenant vérifier s'il peut désérialiser ce contenu, si ce n'est pas le cas, le serveur répondrait avec un code HTTP 415.

Si les données soumises ne sont pas réellement du type de contenu spécifié, ce qui signifie qu'elles ne peuvent pas être désérialisées correctement, le serveur répondrait un code HTTP 400.


Niveau 3.2

Hypermedia As Transfer Engine Of Application State (HATEOS) est une contrainte de maturité de niveau 3 de l'architecture d'application REST qui la distingue des autres architectures applicatives (Ex: Corba).

Il permet la navigation à l’intérieur d’une ressource et de ses actions disponibles. De cette façon, un client n'a pas besoin de savoir comment interagir avec une application pour les différentes actions, car toutes les métadonnées seront intégrées dans les réponses du serveur.

Exemple :

{
   "name": "John Doe",
   "links": [{
         "rel": "self",
         "href": "http://localhost:8080/user/123"
   },
   {
         "rel": "posts",
         "href": "http://localhost:8080/user/123/post"
   },
{
         "rel": "address",
         "href": "http://localhost:8080/user/123/address"
   }
   ]
}

Ou

{
   "name": "John Doe",
   "self": "http://localhost:8080/user/123",
   "posts": "http://localhost:8080/user/123",
   "address": "http://localhost:8080/user/123/address"
}

Cette convention n’est pas à utiliser automatiquement, cela dépend des champs de la taille des ressources et des actions qui peuvent être effectuées sur une ressource.


Niveau 3.3

Le versioning de l'API REST est un modèle d'API REST qui se concentre sur différentes représentations d'une ressource particulière selon sa version.

Le contrôle de version des API doit permettre de garantir la compatibilité descendante d'un service tout en ajoutant de nouvelles fonctionnalités ou en mettant à jour les fonctionnalités existantes pour les nouveaux clients.

Il existe différentes écoles de pensée pour la version de votre API, mais la plupart d'entre elles se répartissent en deux catégories ci-dessous :

•    En-têtes personnalisées : Ajout d'une clé d'en-tête X-API-VERSION par le client:
        - Accept Header : Utilisation de l'en-tête d'acceptation pour spécifier votre version, par exemple :
         Accept: application/apiswappceefov2+json
•    URL :Intégrez la version dans l'URL telle que POST /v2 /articles

La méthode de versioning URL permet d’assurer une meilleure découverte de la ressource.


4. La gestion des erreurs

L'API doit toujours renvoyer des codes d'état HTTP, les erreurs d'API se divisent en 2 types :
•    Codes d'état 4xx séries pour les problèmes client,
•    Codes d'état 5xx séries pour les problèmes serveur.

Au minimum, l'API doit normaliser les erreurs d'état de type 4xx avec le détail de l'erreur au format Json. Il est conseillé d'étendre ce principe aux codes d'état 5xx.

Une API doit retourner un message d'erreur utile dans un format Json. La représentation doit être décrite comme pour toute ressource.

Les erreurs de validation des verbes PUT, PATCH et POST nécessiteront une structuration précise afin de faciliter l’analyse. Il est conseillé d’utiliser une nomenclature des codes d'erreur, en précisant le maximum de détail sur l'erreur.

Exemple:

{
   "code" : 1024,
   "userMessage" : "Impossible de valider un ou plusieurs champ",
   "developerMessage" : "La validation a échoué"
   "errors" : [
      {
      "location" : "firstName",
      "message" : "Le prénom ne peux pas avoir de"
      }
   ]
}

5. Gestion des caches

Il existe 2 approches pour la gestion des caches :
•    Etag
•    Last-Modified


5.1 Gestion des caches

La balise-entité ETag HTTP ou étiquette d'entité (HTTP ETag en anglais) est une partie du protocole de communication HTTP utilisée pour la validation du cache. Un ETag est un identifiant unique et opaque assigné par le serveur web à chaque version d'une ressource accessible via une URL.

Dans une utilisation standard, lorsqu'une URL est récupérée, le serveur renvoie la ressource avec sa valeur ETag correspondante contenant un hachage ou une somme de contrôle de la représentation qui est placée dans un en-tête HTTP "ETag", par exemple: Etag : "686897696a7c876b7e"

Le client peut décider de mettre en cache la ressource ainsi que son ETag. Plus tard, s'il le souhaite récupérer à nouveau la même ressource, il enverra la copie précédemment enregistrée de l'ETag avec la demande dans l’entête "If-None-Match". Le serveur compare l'ETag du client avec l'ETag de la version actuelle de la ressource. Si les valeurs ETag correspondent, cela signifie que la ressource n'a pas changé. Ainsi, le serveur peut renvoyer une réponse avec un code état 304 non modifié. Le statut 304 indique alors au client que sa version en cache est toujours la même et qu'il doit l'utiliser.

5.2 Last-Modified
Cela fonctionne comme pour ETag, sauf qu'il utilise des horodatages. L'en-tête de réponse Last-Modified contient un horodatage au format RFC 1123 qui est validé avec l’entête If-Modified-Since.

HTTP/1.1 OK
Last-Modified: Fri, 16 Jan 2015 10:07:04 GMT
Expires: Fri, 16 Jan 2015 11:07:04 GMT
Cache-Control: max-age=1200,must-revalidate

Le client peut décider de forcer la validation de la ressource en envoyant Cache-control: no-cache dans l'en-tête de la demande. Ceci est particulièrement utile lorsqu'une ressource est mise à jour et que le client a besoin de la dernière version.


6. Sécurité

6.1 SSL Everywhere

Pour une API publique, il est obligatoire de disposer du protocole SSL et pour une API en domaine de confiance, il est fortement conseillé d’utiliser un protocole SSL, en respectant les règles suivantes :
•    Utilisez toujours HTTPS, pour vos appels publics sans aucune exception.
•    Vérifiez toujours les certificats SSL.
•    Ne transférez jamais de données sensibles dans une URL.


6.2 Authentification

Oauth 2 est le meilleur choix pour l'authentification et l'autorisation dans un contexte B2C avec un accès public à l’API.

6.3 Limitation de débit

•    Définir une limite de débit standard pour l'API,
•    Autoriser le dépassement de cette limite par utilisateur et par application,
•    Utiliser un pare-feu qui peut protéger l'API des attaques standard.


7. Localization

Le protocole de négociation de localisation est similaire à la négociation de type de support. Le client exprime son intention en fournissant un en-tête Accept-Language avec des localisations acceptables et leurs valeurs de paramètre d'en-tête q (facteur de qualité relatif), et le serveur décide lequel utiliser pour la réponse.

Exemple:

­GET /policies/123456/coverages ­H Accept-language: en, en-gb; q=0.8

La localisation est sensible à la casse et se compose de:

•    la langue : http://fr.wikipedia.org/wiki/Liste_des_codes_ISO_639-1
•    la région : http://fr.wikipedia.org/wiki/ISO_3166-2

Lorsque le serveur ne peut gérer aucune des localisations demandées par le client, il doit renvoyer 406 Erreur inacceptable plutôt que de présenter la version linguistique par défaut du serveur.


7.1 Heures et dates

L'API doit toujours renvoyer les dates en UTC. Lorsqu'une date est renvoyée sous la forme d'une chaîne, elle doit être formatée en fonction des paramètres régionaux négociés par le client.


7.2 Gestion des devises

Pour les montants en devise, l'API doit renvoyer le code de devise pour chaque champ (ISO 4217).


8. Documentation

Une API nécessite une documentation présentant toutes les informations des différentes rubriques incluses dans les documents, et çela pour chaque ressource. La plupart des développeurs vérifieront les documents avant de tenter tout effort d'intégration:

•    Les documents doivent être faciles à trouver.
•    Les documents doivent montrer des exemples d’appel des services, de la demande à la réponse.
•    Les documents doivent fournir des codes d'erreur.

Swagger est aujourd'hui une solution les plus matures utilisées pour la documentation de l'API REST. La documentation peut être générée directement à partir du code source ou écrite par les concepteurs d'API dans une approche axée sur la conception.


9. Régles de nommages et divers

9.1 Règles de nommage

URL : spinal-case
Corps : camelCase (lowerCamelCase pour les champs et UpperCamelCase pour les entités)
En-tête Http : Spinal-Case

9.2 Body envelope

L'encapsulation des réponses facilite l'inclusion de métadonnées supplémentaires (version mineure, informations de débogage, etc.) ou d'informations de pagination (nombre d'éléments, liens HATEOAS, etc.).

Exemple:

{
   metaData{
   "serverTime":500,{
   "locale":en-GB{
   }{
   "data":{
   }
}

9.3 Compression

Le temps nécessaire pour transférer une demande et une réponse HTTP sur le réseau peut être considérablement réduit lorsque la fonction de compression est activée.

9.4 Json Pretty Print

Une API doit renvoyer un json non indenté pour réduire l'utilisation de la bande passante. Cependant, lors du débogage de la réponse de l'API dans un navigateur par exemple, un tel format de contenu n'est pas très amusant à regarder bien qu'une sorte de paramètre de requête (comme? Pretty = true) puisse être fournie pour permettre une présentation lisible.

9.5 Formats multiple

L'API doit être capable de prendre en charge plusieurs formats. La négociation du format de contenu doit être effectuée à l'aide des en-têtes http Accept (format de réponse) et Content-Type (format du corps de la demande).

Lorsque le client demande un format non pris en charge, le code d'état 415 - Le type de support non pris en charge doit être renvoyé.

Partager cette page: