Partager via


Extension de message basée sur l’API

Remarque

Les extensions de message basées sur l’API prennent uniquement en charge les commandes de recherche.

Les extensions de message générées à l’aide de l’API (basées sur l’API) utilisent un service web pour gérer les demandes et les réponses des utilisateurs et ne nécessitent pas d’inscription de bot. Les extensions de message basées sur l’API sont une fonctionnalité d’application Microsoft Teams qui intègre des API externes directement dans Teams, ce qui améliore la facilité d’utilisation de votre application et offre une expérience utilisateur transparente. Les extensions de message basées sur l’API prennent en charge les commandes de recherche et peuvent être utilisées pour extraire et afficher des données à partir de services externes dans Teams, ce qui simplifie les flux de travail en réduisant le besoin de basculer entre les applications. Les extensions de message basées sur l’API aident vos applications à interagir directement avec des données, des applications et des services tiers, ce qui améliore leurs fonctionnalités. Avec l’extension de message basée sur l’API, vous pouvez :

  • Récupérer des informations en temps réel, telles que la couverture des dernières actualités sur le lancement d’un produit.
  • Récupérer des informations basées sur les connaissances, par exemple les fichiers de conception de mon équipe dans Figma

Regardez la vidéo pour en savoir plus sur la création d’une extension de message basée sur l’API à l’aide de Teams Toolkit :


Extensions de message traditionnelles basées sur un bot Extensions de message basées sur l’API
Les développeurs doivent créer, déployer et gérer un service pour gérer les commandes d’appel à partir du client Teams. Si les API du service final peuvent être décrites à l’aide de la spécification OpenAPI, les développeurs peuvent éliminer le besoin du service de gestion de couche intermédiaire.
Ce service traite la requête entrante et effectue un appel au service final du développeur. Teams peut utiliser directement la spécification OpenAPI pour générer des demandes et communiquer avec le service final du développeur.

Les images suivantes montrent le flux des requêtes utilisateur via les extensions de message traditionnelles et les extensions de message d’API :

Capture d’écran montrant le flux de requête utilisateur entre un utilisateur, un client Teams et un service de bot Teams à l’aide d’extensions de message traditionnelles. Le diagramme montre également comment les spécifications d’API, les modèles de rendu et l’API sont liés les uns aux autres. Flux de requête utilisateur utilisant des extensions de message traditionnelles. Le développeur doit gérer un service de gestionnaire de bot personnalisé, qui gère les demandes d’un bot Teams. Le service gestionnaire envoie une requête au service du développeur lorsqu’une requête est appelée.


Capture d’écran montrant le flux de requête entre un utilisateur, un client Teams et un service de bot Teams à l’aide d’extensions de message d’API. Le diagramme montre également comment les spécifications d’API, les modèles de rendu et l’API sont liés les uns aux autres. Flux de requête utilisateur à l’aide d’extensions de message d’API. Il n’est pas nécessaire d’utiliser un service de gestionnaire géré par le développeur tant que l’interaction est clairement décrite dans la spécification OpenAPI du package d’application.



Voici une séquence d’événements de haut niveau qui se produisent lors d’un appel de commande de requête :

  1. Lorsqu’un utilisateur appelle une commande de requête, les paramètres de la commande de requête sont reçus par le Bot Service Teams.

  2. La commande de requête est définie dans le fichier manifeste de l’application. La définition de commande contient une référence à l’intérieur operationId du fichier de spécification OpenAPI, ainsi que les détails des paramètres rendus par le client Teams pour cette commande. À titre de référence, le operationId à l’intérieur du fichier de spécification OpenAPI est unique à une opération HTTP particulière.

  3. Le Bot Service Teams utilise ensuite les paramètres fournis par l’utilisateur ainsi que la copie de la spécification OpenAPI pour le associé operationId afin de générer une requête HTTP pour le point de terminaison du développeur.

  4. Si l’authentification est requise et est configurée dans le manifeste. Il est résolu en jeton ou clé approprié. Ce jeton ou cette clé est utilisé dans le cadre de la demande sortante. [Facultatif]

  5. Le service de bot Teams effectue la requête HTTP au service du développeur.

  6. Le service du développeur doit répondre conformément au schéma décrit dans la spécification OpenAPI. Il est au format JSON.

  7. Le client Teams doit afficher les résultats à l’utilisateur. Pour convertir les résultats JSON de l’étape précédente en interface utilisateur, le service de bot Teams utilise le modèle de rendu de réponse pour générer une carte adaptative pour chaque résultat.

  8. Les cartes adaptatives sont envoyées au client, qui les affiche dans l’interface utilisateur.

Le diagramme montre le flux de séquence de haut niveau lorsqu’une requête est appelée dans une extension de message basée sur une API.

Configuration requise

Le package de définition d’application inclut divers artefacts attrayants qui prennent en charge les fonctionnalités de cette fonctionnalité. Avant de commencer, assurez-vous d’avoir une compréhension de base des fichiers suivants :

Description OpenAPI (OAD)

Le documenat de description OpenAPI est une norme industrielle adoptée pour décrire les API. Il vous permet d’extraire vos API de leur implémentation, en fournissant des définitions indépendantes du langage qui sont à la fois lisibles par l’utilisateur et lisibles par machine. Le documenat de description OpenAPI décrit les interactions que votre extension prend en charge, ce qui permet à Teams de générer des demandes et de communiquer directement avec votre service sans avoir besoin d’un service de gestion de couche intermédiaire.

Un document de description OpenAPI contient des détails pour communiquer avec le service du développeur. Vérifiez que vous respectez les instructions suivantes pour le document De description OpenAPI (OAD) :

  • Les versions 2.0 et 3.0.x d’OpenAPI sont prises en charge.
  • JSON et YAML sont les formats pris en charge.
  • Le corps de la demande, s’il est présent, doit être application/Json.
  • Définissez une URL de serveur de protocole HTTPS pour la servers.url propriété .
  • Seules les méthodes POST et GET HTTP sont prises en charge.
  • Le document De description OpenAPI doit avoir un operationId.
  • Un seul paramètre obligatoire sans valeur par défaut est autorisé.
  • Un paramètre obligatoire avec une valeur par défaut est considéré comme facultatif.
  • Les utilisateurs ne doivent pas entrer de paramètre pour un en-tête ou un cookie.
  • L’opération ne doit pas avoir d’en-tête ou de paramètres de cookie requis sans valeurs par défaut.
  • Vérifiez qu’il n’existe aucune référence distante dans le document Description OpenAPI.
  • La construction de tableaux pour la requête n’est pas prise en charge ; toutefois, les objets imbriqués dans un corps de requête JSON sont pris en charge.
  • Teams ne prend pas en charge les oneOfconstructions , anyOfallOf, et not (swagger.io).

Le code suivant est un exemple de document de description OpenAPI :

Exemple de document de description OpenAPI
openapi: 3.0.1
info:
title: OpenTools Plugin
description: A plugin that allows the user to find the most appropriate AI tools for their use cases, with their pricing information.
version: 'v1'
servers:
- url: https://gptplugin.opentools.ai
paths:
/tools:
 get:
   operationId: searchTools
   summary: Search for AI Tools
   parameters:
     - in: query
       name: search
       required: true
       schema:
         type: string
       description: Used to search for AI tools by their category based on the keywords. For example, ?search="tool to create music" will give tools that can create music.
   responses:
     "200":
       description: OK
       content:
         application/json:
           schema:
             $ref: '#/components/schemas/searchToolsResponse'
     "400":
       description: Search Error
       content:
         application/json:
           schema:
             $ref: '#/components/schemas/searchToolsError'
components:
schemas:
 searchToolsResponse:
   required:
     - search
   type: object
   properties:
     tools:
       type: array
       items:
         type: object
         properties:
           name:
             type: string
             description: The name of the tool.
           opentools_url:
             type: string
             description: The URL to access the tool.
           main_summary:
             type: string
             description: A summary of what the tool is.
           pricing_summary:
             type: string
             description: A summary of the pricing of the tool.
           categories:
             type: array
             items:
               type: string
             description: The categories assigned to the tool.
           platforms:
             type: array
             items:
               type: string
             description: The platforms that this tool is available on.
       description: The list of AI tools.
 searchToolsError:
   type: object
   properties:
     message:
       type: string
       description: Message of the error.

Pour plus d’informations sur l’écriture de définitions OpenAPI dans YAML, consultez Structure OpenAPI.

Manifeste d'application

Le manifeste d’application est un blueprint pour votre application Teams, qui définit comment et où l’extension de message est appelée dans le client Teams. Il inclut les commandes que votre extension prend en charge et les emplacements à partir desquels elles sont accessibles, tels que la zone de rédaction des messages, la barre de commandes et le message. Le manifeste est lié à la spécification OpenAPI et au modèle de rendu de réponse pour garantir les fonctionnalités appropriées.

Le manifeste d’application contient la définition de commande de requête. Veillez à respecter les instructions suivantes pour le manifeste de l’application :

  • Définissez la version du manifeste de l’application sur 1.17.
  • Définissez sur composeExtensions.composeExtensionTypeapiBased.
  • Définissez composeExtensions.apiSpecificationFile comme chemin d’accès relatif au document De description OpenAPI dans le dossier . Cela lie le manifeste de l’application à la spécification de l’API.
  • Définissez apiResponseRenderingTemplateFile comme chemin d’accès relatif au modèle de rendu de réponse. Cela spécifie l’emplacement du modèle utilisé pour le rendu des réponses de l’API.
  • Chaque commande doit avoir un lien vers le modèle de rendu de réponse. Cela connecte chaque commande à son format de réponse correspondant.
  • La Commands.id propriété dans le manifeste de l’application doit correspondre au operationId dans le document Description OpenAPI.
  • Si un paramètre requis est sans valeur par défaut, la commande parameters.name dans le manifeste de l’application doit correspondre à dans parameters.name le document de description OpenAPI.
  • Si aucun paramètre n’est requis, la commande parameters.name dans le manifeste de l’application doit correspondre au facultatif parameters.name dans le document Description OpenAPI.
  • Vérifiez que le nom des paramètres de chaque commande dans le manifeste de l’application correspond exactement au nom correspondant du paramètre défini pour l’opération dans le document Description OpenAPI.
  • Un modèle de rendu de réponse doit être défini par commande, qui est utilisée pour convertir des réponses à partir d’une API.
  • Les descriptions des commandes et des paramètres ne doivent pas dépasser 128 caractères.

Voici un exemple de manifeste d’application avec des définitions pour les extensions de message basées sur l’API :

Exemple de manifeste d’application
 {
 "$schema": "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.schema.json",
 +  "manifestVersion": "devPreview",
 "version": "1.0.0",
 "id": "04805b4b-xxxx-xxxx-xxxx-4dbc1cac8f89",
 "packageName": "com.microsoft.teams.extension",
 "developer": {
    "name": "Teams App, Inc.",
    "websiteUrl": "https://www.example.com",
    "privacyUrl": "https://www.example.com/termofuse",
    "termsOfUseUrl": "https://www.example.com/privacy"
 },
 "icons": {
    "color": "color.png",
    "outline": "outline.png"
 },
 "name": {
    "short": "AI tools",
    "full": "AI tools"
 },
 "description": {
    "short": "AI tools",
    "full": "AI tools"
 },
 "accentColor": "#FFFFFF",
 "composeExtensions": [
    {
 +      "composeExtensionType": "apiBased",
 +      "authorization": {
 +        "authType": "apiSecretServiceAuth ",
 +        "apiSecretServiceAuthConfiguration": {
 +            "apiSecretRegistrationId": "96270b0f-7298-40cc-b333-152f84321813"
 +        }
 +      },
 +      "apiSpecificationFile": "aitools-openapi.yml",
       "commands": [
       {
          "id": "searchTools",
          "type": "query",
          "context": [
             "compose",
             "commandBox"
          ],
          "title": "search for AI tools",
          "description": "search for AI tools",
          "parameters": [
             {
             "name": "search",
             "title": "search query",
             "description": "e.g. search='tool to create music'"
             }
          ],
 +          "apiResponseRenderingTemplateFile": "response-template.json"
       }
       ]
    }
 ],
 "validDomains": []
 }

Paramètres

Nom Description
composeExtensions.composeExtensionType Compose type d’extension. Mettez à jour la valeur sur apiBased.
composeExtensions.authorization Informations relatives à l’autorisation pour l’extension de message basé sur l’API
composeExtensions.authorization.authType Énumération des types d’autorisation possibles. Les valeurs prises en charge sont none, apiSecretServiceAuthet microsoftEntra.
composeExtensions.authorization.apiSecretServiceAuthConfiguration Détails de capture d’objet nécessaires pour effectuer l’authentification de service. Applicable uniquement lorsque le type d’authentification est apiSecretServiceAuth.
composeExtensions.authorization.apiSecretServiceAuthConfiguration.apiSecretRegistrationId ID d’inscription retourné lorsque le développeur envoie la clé API via le portail des développeurs.
composeExtensions.apiSpecificationFile Fait référence à un fichier de description OpenAPI dans le package d’application. Incluez lorsque type est apiBased.
composeExtensions.commands.id ID unique que vous affectez à la commande de recherche. La demande de l’utilisateur inclut cet ID. L’ID doit correspondre au operationId disponible dans la description OpenAPI.
composeExtensions.commands.context Tableau où les points d’entrée pour l’extension de message sont définis. Les valeurs par défaut sont compose et commandBox.
composeExtensions.commands.parameters Définit une liste statique de paramètres pour la commande . Le nom doit être mappé au parameters.name dans la description OpenAPI. Si vous référencez une propriété dans le schéma du corps de la demande, le nom doit être mappé aux properties.name paramètres de requête ou .
composeExtensions.commands.apiResponseRenderingTemplateFile Modèle utilisé pour mettre en forme la réponse JSON de l’API du développeur à la réponse de carte adaptative. [Obligatoire]

Pour plus d’informations, consultez composeExtensions.

Modèle de rendu de réponse

Remarque

Teams prend en charge les cartes adaptatives jusqu’à la version 1.5. Lorsque vous utilisez le concepteur de cartes adaptatives, veillez à remplacer la version cible par la version 1.5.

Le modèle de rendu de réponse est un format prédéfini qui détermine la façon dont les résultats de votre API sont affichés dans Teams. Il utilise des modèles pour créer des cartes adaptatives ou d’autres éléments d’interface utilisateur à partir de la réponse de l’API, garantissant ainsi une expérience utilisateur transparente et intégrée dans Teams. Le modèle définit la disposition et le style des informations présentées, qui peuvent inclure du texte, des images et des composants interactifs. Veillez à respecter les instructions suivantes pour le modèle de rendu de réponse :

  • Définissez l’URL de référence de schéma dans la $schema propriété pour établir la structure de votre modèle dans le schéma du modèle de rendu de réponse.
  • Les valeurs prises en charge pour responseLayout sont list et grid, qui déterminent la façon dont la réponse est visuellement présentée. Pour plus d’informations sur la disposition, consultez Répondre aux demandes des utilisateurs.
  • Un jsonPath est demandé de nouveau pour les tableaux ou lorsque les données de la carte adaptative ne sont pas l’objet racine. Par exemple, si vos données sont imbriquées sous productDetails, votre chemin JSON est productDetails.
  • Définissez jsonPath comme chemin d’accès aux données ou au tableau appropriés dans la réponse de l’API. Si le chemin pointe vers un tableau, chaque entrée du tableau est liée au modèle de carte adaptative et retourne un résultat distinct. [Facultatif]
  • Obtenez un exemple de réponse pour valider le modèle de rendu de réponse. Cela sert de test pour vous assurer que votre modèle fonctionne comme prévu.
  • Utilisez des outils tels que Fiddler ou Postman pour appeler l’API et vous assurer que la demande et la réponse sont valides. Cette étape est cruciale pour résoudre les problèmes et confirmer que votre API fonctionne correctement.
  • Vous pouvez utiliser la carte adaptative Designer pour lier la réponse de l’API au modèle de rendu de réponse et afficher un aperçu de la carte adaptative. Insérez le modèle De carte adaptative dans l’ÉDITEUR DE CHARGE UTILE CARD et insérez l’exemple d’entrée de réponse dans l’ÉDITEUR DE DONNÉES ÉCHANTILLON.

Le code suivant est un exemple de modèle de rendu de réponse :

Exemple de modèle de rendu de réponse
{
"version": "1.0",
"$schema": "developer.microsoft.com/json-schemas/teams/v1.17/MicrosoftTeams.ResponseRenderingTemplate.schema.json",
"jsonPath": "repairs",
"responseLayout": "grid",
"responseCardTemplate": {
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": [
    {
      "type": "Container",
      "items": [
        {
          "type": "ColumnSet",
          "columns": [
            {
              "type": "Column",
              "width": "stretch",
              "items": [
                {
                  "type": "TextBlock",
                  "text": "Title: ${if(title, title, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "TextBlock",
                  "text": "Description: ${if(description, description, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "TextBlock",
                  "text": "Assigned To: ${if(assignedTo, assignedTo, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "Image",
                  "url": "${image}",
                  "size": "Medium",
                  "$when": "${image != null}"
                }
              ]
            },
            {
              "type": "Column",
              "width": "auto",
              "items": [
                {
                  "type": "Image",
                  "url": "${if(image, image, '')}",
                  "size": "Medium"
                }
              ]
            }
          ]
        },
        {
          "type": "FactSet",
          "facts": [
            {
              "title": "Repair ID:",
              "value": "${if(id, id, 'N/A')}"
            },
            {
              "title": "Date:",
              "value": "${if(date, date, 'N/A')}"
            }
          ]
        }
      ]
    }
  ]
  },
  "previewCardTemplate": {
  "title": "Title: ${if(title, title, 'N/A')}",
  "subtitle": "Description: ${if(description, description, 'N/A')}",
  "text": "Assigned To: ${if(assignedTo, assignedTo, 'N/A')}",
  "image": {
    "url": "${image}",
    "$when": "${image != null}"
    }
  }
 }

Carte d’aperçu

Un aperçu carte modèle dans le schéma du modèle de rendu de réponse est utilisé pour mapper les réponses JSON à un aperçu carte que les utilisateurs voient lorsqu’ils sélectionnent un résultat de recherche. L’aperçu carte développe ensuite une carte adaptative dans la zone de composition de message. La préversion carte modèle fait partie du modèle de rendu de réponse, qui inclut également un modèle de carte adaptative et des métadonnées.

Capture d’écran montrant un exemple d’extension de composition affichant un tableau de cartes d’aperçu lors de la recherche d’un mot spécifique. Dans ce cas, la recherche de « a » dans l’application de test renvoie cinq cartes affichant les propriétés et valeurs « Title », « Description » (tronquée) et « AssignedTo » dans chacune d’elles.

Carte adaptative développée

Exemple de l’aspect de la carte adaptative développée une fois qu’un utilisateur sélectionne un aperçu carte. La carte adaptative affiche les valeurs Title, full Description, AssignedTo, RepairId et Date.

Paramètres

Propriété Type Description Obligatoire
version string Version de schéma du modèle de rendu de réponse actuel. Oui
jsonPath string Chemin d’accès à la section appropriée dans les résultats auxquels responseCardTemplate et previewCardTemplate doivent être appliqués. S’il n’est pas défini, l’objet racine est traité comme la section appropriée. Si la section appropriée est un tableau, chaque entrée est mappée au responseCardTemplate et au previewCardTemplate. Non
responseLayout responseLayoutType Spécifie la disposition des résultats dans le menu volant d’extension de message. Les types pris en charge sont list et grid. Oui
responseCardTemplate adaptiveCardTemplate Modèle permettant de créer une carte adaptative à partir d’une entrée de résultat. Oui
previewCardTemplate previewCardTemplate Modèle permettant de créer un aperçu carte à partir d’une entrée de résultat. L’aperçu obtenu carte s’affiche dans le menu volant de l’extension de message. Oui

Chemin d’accès Json

Le chemin JSON est facultatif, mais doit être utilisé pour les tableaux ou lorsque l’objet à utiliser comme données de la carte adaptative n’est pas l’objet racine. Le chemin JSON doit suivre le format défini par Newtonsoft. Cet outil peut être utilisé. Vous pouvez utiliser l’outil JSON pour vérifier si un chemin JSON est correct. Si le chemin JSON pointe vers un tableau, chaque entrée de ce tableau est liée au modèle carte adaptative et retourne des résultats distincts.

Exemple Supposons que vous disposez du code JSON suivant pour une liste de produits et que vous souhaitez créer un résultat carte pour chaque entrée.

{
   "version": "1.0",
   "title": "All Products",
   "warehouse": {
      "products": [
        ...
      ]
   }
}

Comme vous pouvez le voir, le tableau de résultats se trouve sous « products », qui est imbriqué sous « warehouse », de sorte que le chemin JSON serait « warehouse.products ».

Utilisez https://adaptivecards.io/designer/ pour afficher un aperçu de la carte adaptative en insérant le modèle dans la charge utile de la carte Rédacteur, puis prenez un exemple d’entrée de réponse à partir de votre tableau ou de votre objet et insérez-le dans l’éditeur de données identiques à droite. Assurez-vous que le carte s’affiche correctement et est à votre convenance. Teams prend en charge les cartes jusqu’à la version 1.5, tandis que le concepteur prend en charge la version 1.6.

Conversion de schéma OpenAPI

Remarque

Nous envoyons un en-tête accept-language dans la requête HTTP qui est envoyé au point de terminaison défini dans le document de description OpenAPI. La langue d’acceptation est basée sur les paramètres régionaux du client Teams et peut être utilisée par le développeur pour retourner une réponse localisée.

Les types de données suivants dans le document de description OpenAPI sont convertis en éléments au sein d’une carte adaptative comme suit :

  • string, number, integer, les boolean types sont convertis en TextBlock.

    Exemple
    • Schéma source : string, number, integeret boolean

       name:
         type: string
         example: doggie
      
    • Schéma cible : Textblock

      {
      "type": "TextBlock",
      "text": "name: ${if(name, name, 'N/A')}",
      "wrap": true
      }
      
  • array: un tableau est converti en conteneur à l’intérieur de la carte adaptative.

    Exemple
    • Schéma source : array

          type: array
                    items:
                    required:
                      - name
                    type: object
                      properties:
                      id:
                        type: integer
                      category:
                        type: object
                        properties:
                        name:
                          type: string
      
    • Schéma cible : Container

          {
                    "type": "Container",
                    "$data": "${$root}",
                    "items": [
                      {
                        "type": "TextBlock",
                        "text": "id: ${if(id, id, 'N/A')}",
                        "wrap": true
                      },
                      {
                        "type": "TextBlock",
                        "text": "category.name: ${if(category.name, category.name, 'N/A')}",
                        "wrap": true
                      }
                    ]
                  }
      
      
  • object: un objet est converti en propriété imbriquée dans la carte adaptative.

    Exemple
    • Schéma source : object

      components:
        schemas:
          Pet:
              category:
                type: object
              properties:
                id:
                  type: integer
                name:
                  type: string
      
      
    • Schéma cible : propriété imbriquée dans une carte adaptative

      {
        "type": "TextBlock",
        "text": "category.id: ${if(category.id, category.id, 'N/A')}",
        "wrap": true
      },
      {
        "type": "TextBlock",
        "text": "category.name: ${if(category.name, category.name, 'N/A')}",
        "wrap": true
      }
      
      
  • image: si une propriété est une URL d’image, elle est convertie en élément Image dans la carte adaptative.

    Exemple
    • Schéma source : image

          image:
            type: string
            format: uri
            description: The URL of the image of the item to be repaired
      
      
    • Schéma cible : "Image"

      {
            "type": "Image",
            "url": "${image}",
            "$when": "${image != null}"
          }
      
      

Étape suivante