Passer au contenu principal

Diagnostiquez vos APIs avec le Debug Mode !

Si vous travaillez régulièrement avec des APIs, vous connaissez les difficultés liées à leur sécurisation, leur protection et leur gestion, ainsi qu’à l’élaboration des fonctionnalités de base.

Si vous ne l’avez pas encore fait, vous devriez jeter un coup d’œil à l’API Management.
Pour résumer:

En informatique, l’API management (ou gestion d’APIs) est une discipline qui consiste à exploiter au mieux les APIs sans mettre en péril le système d’information et sans affecter l’expérience utilisateur.

L’API Management, regroupe l’ensemble des procédures, technologies et équipes en charge de la publication sécurisée d’APIs dans une entreprise. Il peut s’agir d’APIs internes au système d’information ou externes destinées à des partenaires.

En d’autres termes, l’API management est un outil de management, comme son nom l’indique, qui permet de gérer la publication, la promotion et la supervision des échanges de données entre un service fournisseur et un service client, au sein d’un environnement sécurisé et évolutif.

Enfin, l’API Management s’appuie sur des plateformes composées d’une passerelle (Gateway), d’une console d’administration et de supervision, d’un portail donnant accès aux développeurs, aux documentations des APIs. Ces systèmes intègrent de plus de fonctionnalités : hybridation, monétisation et streaming.

(voir sur Wikipedia)


L’utilisation de la plateforme open source Gravitee.io API Management (repo GitHub) vous permet de concevoir et gérer le cycle de vie de vos APIs. Grâce aux nombreuses Policies riches et puissantes disponibles, vous disposez d’un énorme éventail d’outils et de techniques pour enrichir vos APIs, tels que :

  • Vérifier l’authentification et gérer les autres aspects de la sécurité
  • Transformer les headers
  • Protocol Mediation
  • Protéger vos backends contre les pics de trafic malveillants ou accidentels

Mais parfois, vos designs deviennent si complexes qu’il est presque impossible de savoir où se situent les problèmes de conception et de configuration lorsqu’ils apparaissent. Pas de panique, le Debug Mode est là pour vous aider. Le Debug Mode est une fonctionnalité qui libère la puissance de l’API Publisher, vous permettant de concevoir une API, de la « shadow » déployer (ne vous inquiétez pas, nous expliquerons plus tard ce qu’est le « shadow deployment ») et de comprendre exactement quelles Policies ont été appliquées à l’appel d’API.

Dans ce blog post, nous allons nous mettre dans la peau d’un éditeur d’API (API Publisher), en examinant une API présentant des comportements étranges. Nous allons parcourir un exemple simple d’API, et étudier non seulement comment utiliser le Debug Mode, mais aussi comment il fonctionne sous le capot.


🙋‍♂️ Qui suis-je ?

Je m’appelle Yann Tavernier (pour en savoir plus sur mon parcours, ça se passe ici !) et je suis développeur dans l’équipe APIM chez Gravitee.io. J’ai eu l’occasion de travailler sur le Debug Mode et je suis ravi de vous guider et de vous expliquer cette fonctionnalité !


🔑 Concepts et composants clés

Avant de nous pencher sur le Debug Mode, nous allons voir un aperçu de tous les concepts et composants clés que nous utiliserons dans cet article.

Composants clés:

  • APIM est la solution d’API Management développée par Gravitee.io.
  • Gateway, c’est le composant d’APIM chargé de traiter les requêtes des clients. En plus d’agir en tant que proxy pour les APIs, il appliquera également la transformation, les contrôles, la limitation de débit, etc. sur les requêtes entrantes et les réponses sortantes.

Concepts clés:

  • APIs, c’est la représentation de votre backend dans APIM, et est composée d’éléments tels que la documentation, les membres, la conception, les propriétés, etc.
  • API Publisher, c’est un rôle dans APIM, représentant l’utilisateur de l’entreprise en charge de la conception et de la publication des APIs.
  • Plan, c’est la couche d’accès et de service située au-dessus d’une API pour les applications consommatrices. Les applications consommatrices doivent s’abonner à un plan pour pouvoir consommer une API.
  • Policy, c’est un service ou une action qui peut être exécuté sur une requête ou réponse d’API pour effectuer des contrôles, des transformations ou d’autres services. Outre les Policies prêtes à l’emploi, vous pouvez également créer les vôtres.
  • API Definition, c’est la représentation exportée de notre API au format JSON. Elle est utile pour rapidement importer une API sur une autre installation.

🎬 Présentation du scénario

Nous allons maintenant présenter un simple scénario pour expliquer comment utiliser le Debug Mode.

Tous nos exemples seront réalisés sur une installation locale. Vous pouvez utiliser cette commande pour exécuter APIM 3.17 avec docker-compose:

cd /tmp && mkdir -p apim && cd apim && curl -L https://raw.githubusercontent.com/gravitee-io/gravitee-docker/master/apim/3.x/docker-compose.yml -o "docker-compose.yml" && export APIM_VERSION=3.17.1 && docker-compose down -v && docker-compose pull && docker-compose up

Pour accéder à l’interface de la console de management, allez à l’adresse suivante: http://localhost:8084.

Les informations d’identification par défaut sont les suivantes:

  • Login: admin
  • Mot de passe: admin

Si vous êtes intéressé par un guide plus détaillé, vous pouvez consulter cet article de Ljubica Lazarevic (en anglais) !

Nous allons nous appuyer sur une API appelée « Library backend ». Vous pouvez l’importer grâce à son API Definition ici.

Ce backend sera accessible sur http://localhost:8082/library-backend et retournera ce jeu de données simulé:

{
   "books": [
       {
           "title": "A tale of two cities",
           "author": "Charles Dickens",
           "_internalReference": "gio_b1"
       },
       {
           "title": "The Lord of the Rings",
           "author": "J.R.R Tolkien",
           "_internalReference": "gio_b2"
       },
       {
           "title": "The Hitchhiker's Guide to the Galaxy",
           "author": "Douglas Adams",
           "_internalReference": "gio_b3"
       }
   ]
}

Nous analyserons ce jeu de données plus tard.

En tant qu’API Publisher, je souhaite concevoir une API, appelée « Library », pour accéder au backend de ma bibliothèque.

Vous pouvez la créer en vous inspirant de la documentation et suivre ce guide étape par étape, ou vous pouvez directement importer l’API Definition résultante.

Tour d’abord, nous devons choisir le type de Plan à utiliser pour mon API. Nous allons choisir deux plans: un plan Keyless, appelé « Free » et un plan Api-Key, appelé « Premium ».

Commençons par concevoir le plan « Free ». Ce plan permets à tout le monde d’accéder à notre API. Pour protéger nos backends, ainsi que pour améliorer les performances, nous voulons gérer la quantité de traffic qui atteindra notre API avec ce plan. Nous limiterons l’accès grâce à la Policy « Rate Limit ». Une chose à noter: comme il s’agit d’un plan Keyless, les applications consommatrices n’ont pas besoin de créer de souscription.

Configuration de la Rate Limit Policy - APIs

Configuration de la Rate Limit Policy – APIs

Comme l’API sera accessible au public, nous voudrons dissimuler certaines données privées dans la réponse, le champ _internalReference. Pour ce faire, nous allons utiliser la JSON to JSON Transformation policy.

Configuration de Json to Json Policy sur le plan Keyless

Configuration de Json to Json Policy sur le plan Keyless

Voici la configuration de la JSON to JSON Policy. Son but est de supprimer le champs _internalReference dans le tableau de books :

[
  {
    "operation": "remove",
    "spec": {
      "books": {
        "*": {
          "_internalReference": ""
        }
      }
    }
  }
]

Déployons l’API (vous pouvez le faire en synchronisant l’API lorsque vous y êtes invité) et appelons là avec un cURL:
L’appel curl http://localhost:8082/library produira ce résultat:

{
   "books": [
       {
           "title": "A tale of two cities",
           "author": "Charles Dickens"
       },
       {
           "title": "The Lord of the Rings",
           "author": "J.R.R Tolkien"
       },
       {
           "title": "The Hitchhiker's Guide to the Galaxy",
           "author": "Douglas Adams"
       }
   ]
}

Nous avons réussi à dissimuler des données internes et sensibles qui étaient exposées par l’API. Cependant, nos équipes de développeurs pourraient bien avoir besoin d’accéder à ces données à des fins de test. Nous allons créer un plan interne (appelé « Internal » sur les captures d’écran), API-Key plan, pour permettre un accès autorisé aux données, en vérifiant que l’API-Key transmise en tant que header ou query parameter est valide et liée à une application grâce à une souscription. Pour en savoir plus, vous pouvez consulter la documentation sur la façon de configurer un plan.

Rappelez-vous, la suppression de _internalReference a été faite sur le plan Freemium. Ici, avec le plan Internal, nous conservons les données originales. Nous allons en profiter pour utiliser la Assign Attributes Policy pour ajouter un attribut interne dans le contexte. Cet attribut sera la concaténation de l’ID de l’application suivi de « -internal » et accessible par la clé « internal ».

Pour ce faire, nous avons configuré la Assign Attribute Policy pour ajouter un attribut internal avec la valeur suivante : {#context.attributes["application"]}-internal.

Configuration de Assign Attribute Policy

Configuration de Assign Attribute Policy

Appelons maintenant l’API avec curl http://localhost:8082/library?api-key=7cc755d1-378b-4099-9650-9ee9330be55c. Le résultat est:

{
   "books": [
       {
           "title": "A tale of two cities",
           "author": "Charles Dickens",
           "_internalReference": "gio_b1"
       },
       {
           "title": "The Lord of the Rings",
           "author": "J.R.R Tolkien",
           "_internalReference": "gio_b2"
       },
       {
           "title": "The Hitchhiker's Guide to the Galaxy",
           "author": "Douglas Adams",
           "_internalReference": "gio_b3"
       }
   ]
}

REMARQUE : Vous avez peut-être remarqué que nous ne pouvons pas voir l’attribut que nous avons défini. En fait, l’attribut ne vit dans la Gateway que le temps de l’appel. Il s’agit d’un comportement de la Policy que nous utilisons, et il est interne à la Gateway.

Enfin, nous allons créer un Flow sur l’API en utilisant à nouveau la JSON to JSON Transformation Policy pour appliquer des remises à un livre en fonction de certaines conditions.

La remise sera appliquée si la réponse est:

  • La requête contient le header « X-Library-Discount »: »pourcentage de réduction ». Par exemple, pour quinze pour cent de remise: "X-Library-Discount":15
  • L’attribut internal n’est pas vide

Par défaut, la valeur de remise sera celle du header « X-Library-Discount », ou 10% par défaut.

Pour cela, nous allons d’abord configurer la condition de la policy: {(#request.headeers['X-Library-Discount'] != null && #request.headers['X-Library-Discount'].size() > 0) || {#context.attributes['internal'] != null}}

Ensuite, nous allons utiliser cette configuration pour la JSON to JSON Policy:

[
 {
   "operation": "shift",
   "spec": {
     "*": "&"
    }
 },
 {
   "operation": "default",
   "spec": {
     "discount": "{#request.headers['X-Library-Discount'] != null ? #request.headers['X-Library-Discount'][0] : 10}%"
    }
 }
]
Configuration de la JSON to JSON Policy au niveau du flow - APIs

Configuration de la JSON to JSON Policy au niveau du flow

L’appel de l’API avec http://localhost:8082/library?api-key=7cc755d1-378b-4099-9650-9ee9330be55cproduira le résultat suivant:

{
    "message":"Request failed unintentionally",
    "http_status_code":500
}
We are in trouble

We are in trouble – via GIPHY

Nous avons quelques problèmes avec notre dernier flow, mais que s’est-il passé ? Il est difficile de le dire en utilisant simplement cURL ou Postman. Plus la complexité du design de l’API augmente, plus le risque de problèmes augmente également. Comment pouvons-nous éviter de déployer notre API auprès de nos utilisateurs avant d’avoir résolu tous les problèmes en cours ?

L’équipe APIM a créé le Debug Mode pour résoudre ce problème précis.


💥 Voici le Debug Mode !

Le Debug Mode permet d’avoir une compréhension et une vue d’ensemble de ce qui se passe dans la Gateway. Grâce à cette fonctionnalité, nous sommes maintenant en mesure d’envoyer une requête à l’aide de notre client HTTP et de voir exactement quelles Policies ont été exécutées, avec leurs entrées et sorties.

Dans la capture d’écran suivante, vous pouvez voir un exemple de flux de demande examiné à l’aide du Debug Mode :

Exemple d'une requête dans le Debug Mode

Exemple d’une requête dans le Debug Mode

La requête utilise la même API-Key que précédemment, et nous pouvons voir que le status de réponse est 500 - Internal Server Error.

Voyons ce que le Debug Mode nous apprends. Le premier élément important de cette fonctionnalité est la timeline. Elle représente chaque Policy qui a été exécutée, sous la forme d’une carte. Une carte est composée de plusieurs éléments:

  • Le nom de la Policy (par exemple, « Assign Attributes »)
  • Son « stage » (soit sur quelle étape elle a été exécutée: Platform, Security, Plan, API): « Plan > Headers »
  • Son temps d’execution (ex: 0,227ms)
Exemple de carte

Exemple de carte de la Timeline

La timeline représente l’ordre réel d’exécution de vos Policies, qui peut avoir changé par rapport à votre design initial. Vous remarquerez peut-être que l’exécution peut être différente de ce que vous aviez prévu !

Si vous êtes un utilisateur régulier de Gravitee, vous êtes probablement habitué à configurer les Policies et à choisir l’un des scopes suivants: REQUEST, REQUEST_CONTENT, RESPONSE, RESPONSE_CONTENT. Pour les scopes REQUEST et RESPONSE, l’exécution de la Policy n’a aucun accès au « content » (ni en lecture ni en écriture), contrairement à REQUEST_CONTENT et RESPONSE_CONTENT.

Nous n’allons pas approfondir ce sujet, mais il est important de noter que la Gateway exécutera d’abord les Policies « headers » (REQUEST / RESPONSE) et ensuite les Policies de « content » (REQUEST_CONTENT / RESPONSE_CONTENT).

Cliquons sur la carte pour explorer les informations qu’elle fournit.

Vue différentielle du Debug Mode

Vue différentielle du Debug Mode

Grâce à la vue différentielle (désolé pour la traduction 😅, pour les habitués de Git, nous appellerons ça un diff), nous pouvons maintenant voir et comprendre comment fonctionne l’Assign Attributes Policy: elle ajoute un attribut dans l’objet Attributes du contexte interne de l’appel.

Alors… pourquoi notre requête a-t-elle échoué ? Scrollons dans la timeline pour trouver la Policy en erreur.

Policy en échec

Policy en échec

C’est ici ! Nous pouvons voir deux icônes apparaître sur notre de carte de JSON to JSON Transformation. En regardant la carte, nous constatons que cette erreur ce produit sur le « stage » API > Body.

If

  • IF… signifie que la Policy est configurée avec une condition: elle est exécutée uniquement si la condition est évaluée à true
  • signifie que la policy est en erreur

En regardant le diff, nous pouvons voir ce message d’erreur: Request failed unintentionally. C’est exactement le même message que nous avons eu avec notre appel cURL. Malheureusement, ce message ne nous en apprends pas beaucoup sur l’origine de l’erreur.

Cependant, le point intéressant est le bloc concernant la Condition:

Condition de la Policy en erreur

Nous pouvons voir que la condition est invalide. Avec une lecture plus attentive, il semble que nous ayons configuré notre condition avec request.headeers au lieu de request.headers.


🛠 Comment fonctionne le Debug Mode pour vos APIs ?

Alors… comment fonctionne exactement le Debug Mode ? Jetons un coup d’oeil sous le capot.

Lorsque vous envoyez une requête grâce au Debug Mode, l’API Gateway détecte cet événement et commence son traitement.

Elle déploie la version actuelle de votre API dans un état particulier que nous appelons « Shadow Deployment ». Cela signifie simplement que l’API est déployée, mais n’est pas accessible publiquement. Ce déploiement est uniquement utilisé par le Debug Mode, ce qui signifie qu’il n’y a aucun risque que vos clients (ou tout autre utilisateur !) accèdent à cette version de votre API !

Vous n’avez pas besoin de déployer votre API de la manière habituelle pour pouvoir la debugger. Cela peut être très utile lorsque vous effectuez des tests pour trouver la bonne configuration pour une Policy.

Voyons comment cela fonctionne:

Debug Mode - APIs

  1. Vous envoyez votre requête grâce au formulaire du Debug Mode.
    • L’API Management va créer un Debug Event et le sauvegarder en base de données.
    • L’identifiant de l’événement est retourné à la Console UI
    • La Console UI va interroger régulièrement la REST API d’APIM jusqu’à ce que l’état de l’événement soit « SUCCESS »
  2. La Gateway se synchronise régulièrement avec la base de données pour vérifier s’il y a des événements avec le statut « TO_DEBUG »
  3. Lorsqu’un événement est trouvé, l’API est déployée en mode « shadow ». Cela implique deux choses:
    • Cette API n’est accessible à aucun utilisateur, seulement par le Debug Mode et seulement pendant la durée de vie de la session Debug.
    • Cette API est construite avec une encapsulation particulière, offrant la possibilité de stocker les informations d’exécution pendant tout le cycle de vie de l’API.
  4. Un appel HTTP interne reprenant la requête de l’utilisateur du Debug Mode est effectué vers cette API. Cela présente l’avantage de reproduire exactement ce qui se passerait si vous essayiez d’appeler votre API avec cURL ou Postman
  5. La Gateway va traiter la requête et transformera les données en fonction des différentes Policies configurées, comme lors d’un vrai appel. La seule différence avec un déploiement classique est que les headers, payload et information de contextes seront sauvegardés dans le contexte du Debug Mode.
  6. Une fois la requête effectuée, l’API est « désinstallée » (undeployed in english 😃) et l’événement est mis à jour avec les informations de Debug.
  7. Enfin, le résultat est affiché à l’utilisateur dans la Console UI.

🧑‍💻 Retour aux affaires !

Rappelez vous, notre condition contenait une faute de frappe, et nous avons corrigé request.headeers en request.headers dans la JSON To JSON Policy.

Correction de la condition

Correction de la condition

Recommençons l’appel dans le Debug Mode:

Appel valide avec le Debug Mode

Appel valide avec le Debug Mode

La réponse est 200 - OK, et nous pouvons voir la remise appliquée dans le corps de la réponse (champs discount).

Le Debug Mode peut également nous indiquer si une Policy ne s’est pas exécutée en raison d’une condition non remplie.

Si nous appelons l’API sans API-Key ou sans header X-Library-Discount, la JSON to JSON Policy ne sera pas appliquées, comme vous pouvez le voir sur la timeline:

Policy non exécutée - APIs

Policy non exécutée

📝 Récapitulons

Nous venons de voir un exemple simple d’APIs défaillantes avec des problèmes de configuration de Policy, et de la manière de la dépanner avec le Debug Mode. Nous avons pu voir et parcourir les flows pour comprendre ce qui se passait réellement et ce qui causait le problème. On a également examiné comment le Debug Mode fonctionne sous le capot.

Nous serions ravis de connaître votre avis et de savoir comment vous utilisez le Debug Mode. Si le sujet vous intéresse et que vous avez des questions, n’hésitez pas à rejoindre notre forum communautaire. L’équipe se fera un plaisir de discuter avec vous !

Gravitee.io

Équipe, stack, locaux…
Découvrez pourquoi les développeurs
aiment Gravitee.io sur leur page entreprise.

Découvrir la page de Gravitee.io

Laisser un commentaire