Skip to main content

API Guidance: Instructions de mise en œuvre des API

Les interfaces de programmation (API) font partie intégrante des systèmes distribués modernes et constituent un maillon essentiel dans la chaîne d’approvisionnement en données dans les organisations modernes axées sur les données. Elles sont donc indispensables dans l’écosystème de partage des données que le Centre de soutien pour le partage de données cherche à favoriser. Dans cette série en trois parties, accompagnée de modules de formation en ligne, nous avons pour objectif de fournir des connaissances regroupées et pratiques aux personnes qui envisagent de développer et de déployer une API et ont donc besoin de comprendre les bases de cette technologie, ainsi qu’à celles qui recherchent des informations supplémentaires sur les facteurs dont il faut tenir compte dans le processus de mise en œuvre.

Ce contenu sera publié de deux manières :

  1. Ici, sur ce site Web, sous la forme d’épisodes publiés chaque mois; et
  2. une fois la série terminée, dans un seul document que vous pourrez télécharger et lire hors-ligne.

Le guide est disponible en anglais, en français et en allemand. Chaque épisode est suivi de modules de formation en ligne concernant les sujets abordés respectivement dans chaque épisode, pour vous aider à tester vos connaissances.

Le deuxième épisode contenait un aperçu des types d’API récents. Le troisième épisode abordera les instructions de mise en œuvre des API et sera axé sur:

  • les interfaces RESTful;
  • les interfaces GraphQL;
  • la conception de la sécurité;
  • la documentation sur les API.

Restez à l’écoute et n’oubliez pas de discuter du matériel en commentant chaque épisode, ou avec vos pairs sur notre forum.  

 

7. Interfaces RESTful

Les interfaces RESTful sont utiles pour transférer des données en vrac et lorsque l’interface de service et les cas d’utilisation respectifs sont fixes.

Si vous commencez à concevoir une API, ne la dérivez pas du code de votre application, par exemple les classes Java. À la place, observez le contexte délimité du domaine et concevez l’API autour des entités principales du domaine et de la fonctionnalité requise. En particulier, une interface REST se concentre sur les ressources. Les ressources peuvent être des objets, des tableaux, des documents, etc., par exemple, les entités de votre domaine principal : autrement dit : toutes les données que vous souhaitez publier. Ainsi, si vous concevez une API REST, vous devez adopter un mode de pensée hypermédia, car l’idée sous-jacente aux interfaces RESTful concerne le fait de lier différentes ressources. N’oubliez pas que les interface REST sont principalement utilisées pour la communication entre les services et les systèmes autonomes, mais moins pour un usage interne.

7.1 Fondamentaux et structure

Pour concevoir une API REST, vous devez veiller aux quatre concepts de base : le protocole HTTP(S) pour le transport, les URL pour l’adressage des ressources, le format de représentation des données et les méthodes prédéfinies pour le protocole HTTP.

Les services basés sur RESTful doivent utiliser HTTPS/2,1 car cela offre un protocole de transport plus sécurisé.

Dans tous les cas, les URL doivent également suivre le modèle de base suivant pour établir l’adresse vers les ensembles de ressources, les ressources spécifiques et les méthodes d’appel des ressources :

/{version}/{collection}/{resource id/{method name}?{query parameters}

Le nom des collections doit être au pluriel et les ressources doivent posséder un identifiant unique. Les identifiants doivent utiliser la notation « Camel case », par exemple, « /v10/myFavoredCollection ».

Le format de représentation des données utilisé dans le corps d’une méthode HTTP doit être JSON ou YAML. La structure des données doit être définie à l’aide d’un langage de définition de schéma connu tel que OpenAPIv3 (voir la section 6 relative à la documentation sur les API). De plus, les en-têtes HTTP « Content-Type » et « Content-Langage » doivent être définis correctement. L’utilisateur d’une API doit être en mesure de sélectionner le format de son choix avec l’en-tête HTTP « Accept ». Chaque ressource doit contenir un attribut « id », qui correspond à l’identifiant unique de la ressource spécifique. Les ressources doivent avoir un format structuré afin d’inclure la totalité des informations de la ressource.

La méthode GET sert à demander/rechercher des ressources spécifiques ou une liste de ressources dans une collection. Les paramètres de recherche doivent être définis afin de limiter le nombre de résultats et de permettre la pagination en évaluant les paramètres « skip » et « limit ». La méthode POST est utilisée pour créer de nouvelles ressources, tandis que la méthode PUT sert à mettre à jour/modifier les ressources. La méthode DELETE, quant à elle, sert à supprimer des ressources spécifiques.

En général, toutes les requêtes et réponses doivent soutenir les en-têtes HTTP pour transférer les méta-informations requises ou utiles, par exemple pour rechercher « Results-Matching », « Results-Skipped » et « Link ».

7.2 Recommandations

Les API peuvent évoluer au fil du temps, aussi est-il important de maintenir la gestion des différentes versions des API. Pour aider les utilisateurs d’une API à estimer l’impact d’une nouvelle version, le numéro de version d’une API doit être sans équivoque, par exemple en adoptant les règles de Spécification de la gestion sémantique2 de version (SemVer). Une API doit soutenir la version actuelle et la version précédente pendant une période intermédiaire. Le numéro de version doit faire partie de chaque URL, par exemple, https://api.expample.org/v1/... ; sinon, il peut être établi selon le paradigme hypermédia avec les en-têtes HTTP, par exemple, Accept: application/vnd.exemple ;version=1.0.

Les résultats d’une requête GET doivent également pouvoir être mis en cache. Pour cela, la réponse doit inclure les en-têtes HTTP corrects pour ETag, Last-Modified, If-None-Match et If-Not-Modified-Since. S’il y a trop de requêtes sur une période, la requête doit être rejetée avec un message d’erreur approprié.

En général, un code d’état HTTP adéquat doit être fourni avec chaque réponse à une requête HTTP. Évitez d’utiliser vos propres codes d’état et préférez-leur un des codes d’état HTTP prédéfinis.

Au-delà des fonctions commerciales, une API doit fournir des endpoints pour la gestion des opérations internes. Chaque API doit assurer une vérification de l’état de santé, de présence et de préparation, par exemple avec les “/healthz”, “/healthz/liveness” and “/healthz/readiness”. La « présence » signifie que le service est fondamentalement disponible, tandis que le terme « préparation » indique que le service accepte immédiatement les nouvelles requêtes et que tous les services utilisés par ce service sont prêts eux aussi.

De plus, il est recommandé de faire en sorte que le service fournisse des mesures à des fins de surveillance interne, par exemple avec l’URL « /metrics ». Pour cela, les mesures peuvent utiliser le format d’exposition textuel de Prometheus pour demander les valeurs des indicateurs. Les indicateurs doivent inclure des éléments tels que l’utilisation, les erreurs et la performance. Pour déboguer les services, un identifiant de traçage unique doit être ajouté aux en-têtes, par exemple, « Tracing ». L’identifiant de traçage doit être unique, transmis aux autres services appelés, ajouté immédiatement à chaque appel (s’il n’est pas présent) et inclus dans les messages journal.

7.3 Liens utiles

Module eLearning pour le chapitre 7

 

8. Interfaces GraphQL

Les interfaces GraphQL sont utiles si vous souhaitez fournir les données d’une manière plus flexible. Cela est particulièrement pratique si les cas d’utilisation ne sont pas tous connus à l’avance ou s’ils changent fréquemment ; par exemple, dans le cas d’une interface utilisateur servie par une API et pour laquelle les données requises changent souvent. GraphQL vous permet de fournir des vues spécifiques des données de votre backend, selon un modèle de données complexe ne nécessitant qu’un seul point d’entrée.

Selon votre cas d’utilisation, il est également possible de déployer une interface GraphQL avec une interface RESTful.

8.1 Fondamentaux et structure

Pour concevoir une API GraphQL, vous devez veiller aux quatre concepts de base, tout comme avec les interfaces RESTful : le protocole HTTP(S) pour le transport, les URL pour les points d’entrée GraphQL, le(s) modèle(s) de données et les méthodes prédéfinies pour le protocole HTTP.

Les services basés sur GraphQL doivent utiliser le protocole de transport HTTPS/2 pour des raisons de sécurité.

L’URL du point d’entrée GraphQL devrait avoir la structure suivante :

              /{version}/gql/{user role}

Comme mentionné ci-dessus, une seule API GraphQL est en principe capable de fournir un accès uniforme à une base de données entière, à condition qu’un modèle de données et des spécifications de requêtes appropriés aient été mis en œuvre. Cependant, en pratique, il est toutefois recommandé d’utiliser plusieurs points d’entrée, idéalement, un par rôle utilisateur. Paradoxalement, la raison de cette recommandation est précisément que les API GraphQL seraient capables de servir de nombreux utilisateurs différents avec de nombreuses requêtes de données différentes. Cela peut sembler étrange, car les avantages supposés des API GraphQL sont leurs prouesses techniques et leur flexibilité. Mais ces caractéristiques posent également des problèmes de sécurité, si un point d’entrée générique est utilisé par de nombreux utilisateurs différents avec des rôles différents qui demandent des données à toute la base de données de manière incontrôlée.

Les recommandations en matière de bonnes pratiques indiquent que les API doivent être mises en œuvre conformément à une politique de sécurité unique. Le meilleur moyen de réguler cela, dans le cas d’une API GraphQL, est de proposer différents points d’entrée basés sur les rôles aux différents utilisateurs. Ces points d’entrée doivent être mis en œuvre de manière cohérente à partir d’un « Point d’application de politique », c’est-à-dire qu’ils doivent valider les données d’entrée de manière syntaxique (par rapport à un schéma) et vérifier l’authentification et l’autorisation de l’utilisateur pour chaque requête. L’autorisation en particulier doit être basée sur le « Contrôle d’accès basé sur les rôles » (RBAC). Si chaque rôle est associé à un modèle de données spécifique, le type d’informations qu’un utilisateur ayant un rôle spécifique peut afficher ou modifier doit être immédiatement évident.

Le modèle de données de chaque point d’entrée doit être complet et bien structuré pour le rôle utilisateur concerné. Les modèles de données doivent, au minimum, être définis à l’aide du langage de définition de schéma (SDL) de GraphQL ; idéalement, ils doivent utiliser la norme OpenAPIv3 (voir la section Documentation sur les API) et convertir le fichier SDL à partir du fichier de spécifications OpenAPIv3.3,swagger-to-graphql, https://github.com/yarax/swagger-to-graphql

Pour exporter, échanger et demander des données, l’API GraphQL doit fournir l’opération « query ». L’opération « mutation » ne doit pas être fournie dans ce contexte. L’API peut fournir l’opération « subscription » afin d’informer les utilisateurs abonnés en cas de mise à jour des données.

8.2 Recommandations

Un environnement de développement (IDE) tel que GraphQL doit être disponible dans l’API, en particulier pour les API externes qui échangent des données avec des tiers. Cela permet aux utilisateurs d’explorer l’espace de données et de tester les expressions GraphQL. Il doit également aider à accélérer le développement de nouveaux scénarios ou l’intégration de nouveaux partenaires.

Les API sont très susceptibles d’évoluer au fil du temps, aussi est-il important de gérer les différentes versions des API. Pour aider les utilisateurs d’une API à estimer l’impact d’une nouvelle version, le numéro de version d’une API doit être sans équivoque et adopter les règles de Spécification de la gestion sémantique4 de version (SemVer). Une API doit soutenir la version actuelle et la version précédente pendant une période intermédiaire. Le numéro de version doit faire partie de chaque URL, par exemple, https://api.example.org/v1/gql/... ; sinon, il peut être établi selon le paradigme hypermédia avec les en-têtes HTTP, par exemple, Accept: application/vnd.exemple ;version=1.0. Comme GraphQL est lui-même très flexible vis-à-vis des changements, notamment en ce qui concerne les extensions du modèle de données, seules les versions majeures doivent être indiquées.

Les résultats d’une requête GraphQL doivent pouvoir être mis en cache. Par conséquent, l’identifiant des ressources du modèle de données doit être unique.

{ "starship": { "id": "3003", "nom": "Navette impériale" } }

Le point d’entrée de l’API GraphQL doit également permettre une vérification de l’état de santé, de présence et de préparation, par exemple avec les URL « /healthz », « healthz/liveness » et « /healthz/readiness ». La « présence » signifie que le service est fondamentalement disponible, tandis que le terme « préparation » indique que le service accepte immédiatement les nouvelles requêtes et que tous les services utilisés par ce service sont prêts eux aussi.  L’interface GraphQL doit également permettre l’utilisation. Pour le débogage, l’utilisation et le transfert d’un ID de traçage doivent être mis en œuvre.

8.3 Liens utiles

GraphQL – A query language for your API, https://graphql.org

GraphQL or Bust, https://nordicapis.com/api-ebooks/graphql-or-bust/

GraphiQL – GraphQL IDE Monorepo, https://github.com/graphql/graphiql

GraphQL Playground, https://github.com/prisma/graphql-playground

 

9. Conception de la sécurité

Les considérations en matière de sécurité doivent faire partie intégrante de la conception d’une API, et ce dès le départ. En général, une mise en œuvre doit toujours être sécurisée de par sa conception, afin d’éviter les comportements imprévus ou les attaques permises par des défauts. La mise en œuvre doit garantir une utilisation valide de l’interface, par exemple en appliquant une validation d’entrée forte. De plus, elle doit éviter les défaillances communes, telles que les dépassements de tampon. Tous les événements et erreurs doivent être continuellement enregistrés en détail dans un journal d’audit afin de permettre l’analyse des problèmes et des questions de sécurité.

9.1 Communication

Nous vous recommandons vivement de sécuriser tout le trafic pour des raisons de sécurité et de confidentialité des données. Pour cela, il faut assurer la sécurité de la couche de transport pour les communications internes comme pour les communications externes. Il faut donc utiliser le protocole HTTP(S)/2 comme touche de transport. L’accès à un service par HTTP ou avec d’anciens protocoles de chiffrement tels que TLS 1.2 (et versions antérieures) doit être refusé. Les actions de sécurité telles que la mise en œuvre du HTTP Strict Transport Security Protocol (HTTPS) et Perfect Forward Secrecy (PFS) doivent être prises en charge.

S’il y a trop d’appels pendant une période donnée, le service doit refuser temporairement la requête et indiquer ce refus en affichant un code d’état, par exemple, « 429 Too Many Requests ». Pour éviter ces problèmes, le service doit envisager de limiter le taux de requêtes en indiquant des limites de taux, par exemple à l’aide des en-têtes X-Rate-Limit-Limit, X-Rate-Limit-Remaining et X-Rate-Limit-Reset dans une réponse.

9.2 Authentification et autorisation

À l’exception des données publiées en tant qu’Open Data, chaque utilisateur doit s’authentifier pour accéder à un service. Les utilisateurs connus doivent également pouvoir s’authentifier. L’authentification doit être mise en œuvre au moyen de mécanismes communs tels que OAuth2 ou OpenID. Si un service communique avec un autre, il doit également s’authentifier, par exemple à l’aide d’un jeton API renouvelé régulièrement et basé sur un système de gestion de secrets comme Vault.5

L’autorisation pour accéder à une fonction d’un service doit reposer sur un concept de sécurité « Contrôle d’accès basé sur les rôles » (RBAC). Pour chaque rôle, il est essentiel de déterminer de manière compréhensible les informations que les utilisateurs d’un groupe donné peuvent consulter, ainsi que les droits de ces derniers.

L’autorisation doit être mise en œuvre au moyen d’un « bearer token », tel qu’un JSON-Web-Token6 (JWT) signé, dans l’en-tête HTTP d’une requête. Les demandes du jeton doivent au minimum contenir l’émetteur (iss), le sujet (sub), l’audience (aud) et la date d’expiration (exp).

 

10. Documentation sur les API

Du point de vue des utilisateurs, une documentation de qualité représente une partie essentielle de toute API. Pour s’assurer que des parties externes puissent utiliser une API, il faut veiller à ce que sa documentation soit compréhensible, correcte, actuelle, complète et exhaustive. De plus, la documentation doit être publique et disponible gratuitement. Une bonne documentation, associée à une conception bien pensée et à une mise en œuvre solide, est la clé d’une API réussie.

L’API doit être définie en premier à partir des cas d’utilisation dérivés de la conception axée sur le domaine et des processus métier. Pendant la mise en œuvre de l’API, les expériences doivent évoluer et être utilisées pour améliorer progressivement la spécification.

10.1 Fondamentaux de la mise en œuvre

La documentation et le code de l’interface doivent être générés à partir de la spécification formelle de l’API. Cette spécification doit donc être définie au moyen du langage de définition de schéma et d’interface (SDL) OpenAPIv3.7 Ce SDL doit être utilisé pour définir les API RESTful, les API GraphQL, les liens Web et les flux et événements.

La spécification doit définir le(s) serveur(s), les mécanismes de sécurité, les points d’entrée et tous les modèles de données.

Chaque élément de la spécification doit être expliqué de manière précise et exhaustive. Les champs doivent être définis le plus précisément possible, par exemple en fournissant l’attribut « format » pour tous les champs et en décrivant les valeurs des chaînes personnalisées à l’aide d’expressions régulières (regex) :

              { "name": "color", "type": "string", "format": " ’red’ | ‘blue’ | ‘green’ " }

Les champs de description doivent être utilisés pour décrire la finalité, la fonctionnalité, l’utilisation et le contexte de l’API elle-même et de tous ses éléments. Les champs de description doivent contenir un texte structuré ou formaté en utilisant la syntaxe markdown.

Tous les codes d’état HTTP pouvant être affichés doivent également être énumérés et expliqués.

10.2 Recommendations

Toute la documentation doit inclure les cas d’utilisation, l’histoire des domaines,8 des schémas séquentiels, des exemples de code et d’autres illustrations pour expliquer l’utilisation et la fonctionnalité de l’API.

Les API évoluant au fil du temps, la documentation doit inclure un historique des modifications dans chaque nouvelle version.

La documentation doit être disponible gratuitement en ligne sur une page Web, dans un document électronique imprimable (PDF), et doit être accessible à partir d’un lieu connu. Elle doit être générée automatiquement et mise à jour selon une chaîne de processus CI/CD.

Enfin, la documentation doit être complétée par des cas de tests présentés sous forme lisible et exécutable, par exemple en utilisant les tests orientés comportement.9

 

C’est la fin de la série d’instructions sur les API. N'oubliez pas de discuter du matériel en commentant chaque tranche ou avec vos pairs dans notre forum. Testez également vos connaissances dans les modules d'apprentissage en ligne de l'API SCDS: https://elearningcourses.eudatasharing.eu/fr/apiguidance/#/​​​​​​​

 

API Guidance: Instructions de mise en œuvre des API
Image credit:
(C) 2020 Support Centre for Data Sharing