pulen - stock.adobe.com

Conception d’API : les meilleures pratiques pour bien les entretenir

Des directives communes consacrées à la conception des API permettent d’améliorer leur fonctionnalité et leur flexibilité. Suivez ces bonnes pratiques pour vous aider à entretenir votre jardin florissant d’API REST.

Les API fournissent souvent aux équipes de développement le soutien nécessaire pour traiter de nombreux problèmes spécifiques aux microservices. Par exemple, elles peuvent agir comme un mécanisme qui découple la logique commerciale de l’interface utilisateur. Cela permet, entre autres, de reproduire les rôles de l’application pour les réutiliser, ou même isoler des fonctionnalités pour simplifier les tests et le déploiement.

Malheureusement, les API peuvent également introduire des problèmes. Le déploiement fréquent d’interfaces de programmation (API) peut rapidement créer un système logiciel semblable à un jardin envahi par la végétation, truffé de mauvaises herbes, de bugs, d’intégrations défaillantes et de cas d’usage mal adaptés. Les collections d’API surchargées empêchent des modifications sans provoquer de défaillances. Plus communément, elles limitent la visibilité nécessaire pour reconnaître les possibilités d’optimisation des fonctionnalités.

Un schéma de conception d’API approprié peut contribuer à atténuer ces problèmes courants. Les directives suivantes s’appliquent spécifiquement à REST, et sont principalement destinées aux développeurs et aux architectes qui gèrent déjà une collection variée d’implémentations, de méthodes et de langages dédiés à leurs API. De la conceptualisation de haut niveau aux normes d’interface en passant par les tests d’API, ces conseils vous aideront à entretenir votre jardin florissant peuplé d’interfaces de programmation.

Définissez et documentez votre API depuis un seul environnement

Un nombre inquiétant de sociétés ne disposent pas d’un répertoire central contenant un catalogue de leurs API existantes, de la documentation sur la manière de les utiliser et des enregistrements des versions et des modifications. Au lieu de cela, chaque équipe conserve sa propre réserve d’API, en s’appuyant sur les connaissances des développeurs et les bases de code volumineuses des entreprises.

Les responsables du développement devraient plutôt créer une procédure permettant d’ajouter de nouvelles API à une sorte de système centralisé et modifiable, tel qu’un wiki. Créez une carte heuristique qui énumère les dépendances des API, et ajoutez des liens vers une page wiki décrivant l’API pour chaque nœud de la carte. Ces descriptions doivent utiliser un format de modèle standard qui décrit l’API, les consommateurs, les responsables, son emplacement dans le code et les tests qui servent d’exemples. Par exemple, le langage et l’outil open source OpenAPI est couramment utilisé pour définir et documenter les interfaces des API.

Une définition stricte de l’API comprend les commandes associées, les protocoles HTTP, les URL, le statut, les codes d’erreur et la structure de la charge utile. Vous trouverez ci-dessous un exemple de définition d’OpenAPI, extrait de Swagger, un outil OpenAPI. Redoc et DapperDox prennent également ce type de documentation d’API et créent des pages Web riches et exploitables.

    paths:
      /users/{userId}:
        get:
          summary: Returns a user by ID.
          parameters:
            - name: userId
              in: path
              required: true
              description: Parameter description in CommonMark or HTML.
              schema:
                type : integer
                format: int64
                minimum: 1
          responses:
            '200':
              description: OK

Utilisez les protocoles HTTP pour définir les actions

Vous n’avez pas besoin d’utiliser la commande /getorder si vous utilisez déjà HTTP GET pour passer des appels. Cette URL peut être aussi courte et simple que /order/12345 – le payload en résultant sera l’information sur l’appel.

En règle générale, vous voudrez utiliser ces requêtes HTTP courantes :

  • POST (créer une commande pour une ressource) ;
  • GET (récupérer l’information) ;
  • PUT (mettre à jour et remplacer l’information) ;
  • PATCH (mettre à jour et modifier les informations) ; et
  • Delete (supprimer l’item).

Vous pouvez également utiliser PUT pour créer des ID si le client sélectionne lui-même le numéro d’ID.

Rendre toutes les fonctionnalités compatibles CRUD

Les éléments de création, lecture, mise à jour et suppression (CRUD) se combinent pour permettre aux développeurs de créer de nouvelles fonctionnalités et de les tester. Il est toutefois courant qu’une API ne nécessite pas la structure CRUD complète. Par exemple, une application mobile peut dépendre spécifiquement de la fonction de lecture. Ou encore, un développeur peut ajouter « create », mais penser « j’ajouterai la fonction Delete plus tard ». Parfois, le plus tard ne vient jamais.

Gagnez du temps sur le long terme. Mettez en place une capacité CRUD complète dans le cadre d’un même déploiement.

Définir une politique d’autorisation basée sur les rôles

Certains utilisateurs peuvent créer leur propre compte dans une application particulière, mais n’ont pas la permission de le supprimer. D’autres utilisateurs peuvent avoir la permission de lire, mais pas de mettre à jour, créer ou supprimer une ressource. L’authentification prouve qu’une personne peut se connecter, tandis que l’autorisation indique qu’elle peut accéder à une ressource. En général, les services RESTful le font soit par interaction avec le protocole Lightweight Directory Access (LDAP, pour les employés), soit par un objet de profil client pour les produits logiciels avec des clients.

Favorisez des temps de réponse de bout en bout inférieurs à la seconde

Les API REST sont conçues pour être synchrones. Visez 100 millisecondes pour les services internes sans dépendance HTTP, et une limite supérieure d’environ une seconde pour les services complexes à l’intérieur du centre de données. Si un appel de fonction prend trop de temps, comme la création d’un compte, ne le laissez pas simplement s’exécuter longtemps. Revenez plutôt avec un accountID, ou au moins avec un jeton que le client pourra utiliser plus tard pour consulter le compte. Créez des lignes directrices pour les délais et essayez d’éviter un processus de vote qui n’enregistre que l’heure de fin d’un processus et non le moment où il a commencé.

Hiérarchie des nids

Les données structurées existent sous forme de relations, ou de hiérarchie. Ces relations vous permettent de tirer un groupe plus important, ou de les répartir dans ce groupe pour un élément spécifique. À l’intérieur de cet item, il peut y avoir plus de détails ou de sous-items.

Utilisez une hiérarchie imbriquée pour définir les attributs. Par exemple, imaginez que vous avez une requête GET pour un produit appelé /products/:productid. La demande GET pour tous les examens ultérieurs devrait être /products/:productid/reviews, et une requête GET pour un examen spécifique devrait se lire /products/:productid/:reviewid. Cela peut être fait avec /reviews/:reviewid, et vous pouvez activer les deux – l’utilisation systématique de cette convention améliorera la vitesse de montée en puissance et réduira le risque d’erreur, tout en améliorant la possibilité de découverte et en évitant les arguments contradictoires.

Appliquez un formatage cohérent

Faites preuve de diligence dans vos choix de formatage de conception d’API pour vous aider à conserver votre organisation claire et nette, et éviter toute confusion ou erreur.

Il est souvent judicieux d’utiliser des conventions standard, telles que des noms au lieu de verbes dans les URL que vous créez : /tasks/, /todos/, /orders/, et ainsi de suite. Les verbes tels que create, get, update ou delete sont définis dans le type de requête http (POST, GET, etc.). Leur ajout à l’URL est redondant et rend l’URL imprévisible.

La convention standard est /objecttypes/ pour l’objet, puis l’identifiant unique pour l’objet. Par exemple, un GET sur /tasks/123456 obtiendrait l’information sur la tâche 123456.

Une autre bonne idée est de formater toutes les URL en minuscules et de forcer le serveur à suivre le même chemin. Un appel à /products devrait renvoyer les mêmes résultats que /Products ou /PRODUCTS. Suivez l’ancien adage UNIX : soyez précis dans la façon dont vous traitez les résultats, mais généreux dans les données que vous acceptez.

Autorisez le tri et le filtrage

Vous pouvez implémenter un tri et un filtre sur l’URL elle-même avec des paramètres de requête. /products?name="*testing* » renvoie tous les produits qui contiennent le mot testing. La documentation montre quels sont les paramètres disponibles. Utilisez ?sort=ASC ou ?sort=DESC pour indiquer comment renvoyer les résultats, ce qui peut devenir plus complexe.

En substance, le filtre met en œuvre la recherche, tandis que le tri permet à la requête de modifier la préférence d’ordre. Ce sont deux des fonctions les plus courantes dans le commerce électronique, ou dans toute base de données. Bien que la programmation extrême dise « You are not Gonna Need It » (YAGNI), pensez au moins à la manière de construire et de publier les URL, de sorte que chacun puisse les mettre en œuvre plus tard sans modifier son comportement initial.

Rendre la pagination programmable

Cela ressemble à un tri et à un filtrage. La manière la plus simple d’y parvenir pourrait être /products?name="*testing* » ? limit=10?offset=10. Cela donnerait la deuxième série de dix résultats. Cela permet aux programmeurs de modifier la longueur des pages avec des paramètres. Utilisez des filterNames chaque fois que cela est possible pour simplifier la création de requêtes dans la base de données.

Utiliser JSON pour la charge utile

Le format JavaScript Object Notation (JSON), est la norme de facto pour les API REST. Une organisation qui utilise largement les technologies Microsoft peut choisir d’utiliser le protocole SOAP (Simple Object Access Protocol), qui prend en charge le langage WSDL (Web Services Description Language). Si vous dirigez votre application client vers un fichier WSDL, vous pouvez écrire du code sur l’API presque comme s’il s’agissait d’une librairie de code.

REST, cependant, ne nécessite aucune définition d’interface spécifique et offre une prise en charge plus large des types de données en sortie. Si votre API doit interagir avec une technologie non Microsoft, SOAP peut causer certains problèmes d’interopérabilité.

Utilisez les bibliothèques JSON standards

Résistez à la tentation de manipuler les objets comme des strings, ou utilisez des expressions régulières pour obtenir les données dont vous avez besoin. Au lieu de cela, créez une bibliothèque JSON pour chaque langage que vous utilisez. Les programmeurs peuvent toujours conserver la flexibilité du langage, mais ils utiliseront la bibliothèque pour extraire des données ou ajouter des données à la charge utile. Vous trouverez ci-dessous un programme client simple en Python qui obtient un objet de réponse, l’examine pour détecter une erreur et imprime un élément spécifique du JSON.

import json
import requests

response = requests.get('https://jsonplaceholder.typicode.com/todos/1')
if response.status_code != 200:
# This means something went wrong.
        raise ApiError('GET /todos/ {}'.format(resp.status_code))
jsonobj = json.loads(response.text)
print jsonobj['title']

L’API est une API publique, JSONPlaceholder, donc le code fonctionne nativement dans la plupart des versions modernes de Python. Sur un système Mac ou Linux, vous pouvez l’enregistrer dans un fichier texte appelé « get.py » et ensuite lancer pything get.py depuis la ligne de commande pour le voir s’exécuter. Sur un PC, vous devrez installer Python pour ce faire.

Utilisez les bibliothèques de réseau et REST

Les programmeurs doivent développer une méthode standard pour travailler sur le client et le serveur, partager le code et collaborer. L’époque où l’on utilisait la bibliothèque de sockets en C pour créer son propre réseau est révolue depuis longtemps.

Le code ci-dessus utilise Response, un objet en Python qui enregistre et stocke la réponse d’un serveur à une requête HTTP. Express.js est un autre cadre d’API REST pour Node.js qui permet aux développeurs de créer un objet Response et de coder des réponses personnalisées à GET, PUT, DELETE. Ensuite, ils peuvent simplement appeler un numéro de port spécifique à l’aide de la commande. listen.

Utilisez toujours un parseur natif

Lorsque vous consommez un format de données tiers qui n’est pas le JSON, il peut être tentant de manipuler directement des chaînes de caractères. Au lieu de cela, si ces données sont un format tel que XML, chargez la chaîne dans une structure de données conçue pour traiter ce format. Les manipulations de strings et les expressions régulières peuvent fonctionner aujourd’hui, mais si vous en utilisez suffisamment souvent et que le format XML change, le code peut se détériorer de manière inattendue.

Prenons par exemple cet extrait de code :

<Employee>
  <EmployeeID>12345</EmployeeID>
  <FirstName>Matthew</FirstName>
  <LastName>Heusser</LastName>
</Employee>

Une simple manipulation de la chaîne de caractères peut permettre de rechercher la troisième ligne, de supprimer le XML et de le placer dans une variable Prénom, puis de rechercher la quatrième, de faire de même et de la placer dans la variable Nom. Lorsque l’autre application introduit un champ MiddleName, l’application ne commet pas d’erreur ; elle indique plutôt le LastName comme second prénom.

def execute_a_check(row)
    data = row.split(",")
    url = data[0]
    compare = data[1]
    match = data[2]
    comment = data[3]
    command = "curl -s -H " + '"' + 'Accept: application/json" ' + url
    output = `#{command}`
    output = output.gsub("\n","")
    output = output.gsub("\r","")
    output = output.gsub(",","|")
    if match == "Y" then
      escaped =  Regexp.new(Regexp.escape(compare)).to_s()
      result = (output=~/#{escaped}/)
      @tapoutput.ok(result, comment)
    else
      @tapoutput.ok(output == compare, comment)
    end
  end
end

Les tests obligatoires

Les tests servent de documentation alternative ; ils expriment par l’exemple ce que le logiciel doit faire. Divers outils de test des API prennent ces exemples et les enregistrent. Pour les projets de moindre envergure, on peut utiliser un outil de ligne de commande tel que curl.

La preuve de concept suivante pour les tests d’API prend un array comme entrée. Il comprend l’URL à appeler, ce qu’il faut comparer, les données à attendre et un commentaire. Vous pouvez trouver le système complet dans GitHub ; la fonction Ruby de base apparaît ci-dessous.

Révisez vos connaissances des API modernes

Il est toujours bon de renforcer vos connaissances sur les décisions relatives à la conception des API. Les ouvrages d’O’Reilly, REST API Design Rulebook et aux éditions Manning, API Design Patterns, examinent les normes d’interface de REST. Toujours chez Manning, Microservices Patterns traite de la manière d’enchaîner ces conceptions pour créer des modèles hybrides complexes, tels que les backends pour les frontends et la passerelle API.

L’ensemble de règles dit « douze facteurs », permettant de créer des applications SaaS sur le Web, constitue une autre ressource utile. Elles ne concernent pas spécifiquement la conception d’API, mais comprennent de bonnes indications pour la gestion du code, des déploiements, de l’infrastructure, des configurations, des dépendances, etc.

Pour approfondir sur Outils de développement