Définir des options d'API avancées

Cette page décrit comment définir des options de configuration avancées, telles que les mappages d'entrée et les propriétés virtuelles, pour les fournisseurs de types. Pour en savoir plus sur les types, consultez la section Présentation des types. Pour en savoir plus sur les fournisseurs de type, consultez la fiche sur l'intégration avec Deployment Manager.

Si vous tentez d'intégrer une API qui ne répond pas aux exigences relatives aux API définies par Deployment Manager, vous pouvez utiliser des mappages d'entrée et des propriétés virtuelles pour vous aider à résoudre ces incohérences. Les mappages d'entrée vous permettent de fournir des mappages explicites de paramètres d'API en cas d'ambiguïté. Les propriétés virtuelles vous permettent de fournir des propriétés arbitraires qui n'existent pas dans les API sous-jacentes afin de simplifier les entrées et de masquer les complexités de l'API pour vos utilisateurs.

La mise en œuvre d'options de configuration avancées nécessite une connaissance approfondie de l'API pour laquelle vous créez le fournisseur de types. Étant donné que les API peuvent varier considérablement des unes aux autres, cette page fournit des conseils et des exemples d'ordre général, mais aucune recommandation spécifique à des API.

Avant de commencer

Scénarios courants nécessitant des options de configuration avancées

Nom de propriété utilisé plusieurs fois avec différentes valeurs

Dans certaines API, la même propriété ou le même nom de paramètre peut être utilisé dans plusieurs méthodes, mais avec des valeurs différentes. Par exemple, une API peut spécifier que le paramètre name utilisé pour créer une ressource (requête POST) présente la valeur foo/bar, alors que le même champ name utilisé pour les requêtes de mise à jour (PATCH ou PUT) présente la valeur foo/bar/baz.

Valeurs de propriété renvoyées dans la réponse de l'API

Certaines méthodes d'API requièrent une valeur générée par le serveur qui est renvoyée lorsque vous effectuez une requête GET sur la ressource. Par exemple, une API peut nécessiter un paramètre etag pour effectuer des demandes de mise à jour lors de la mutation d'une ressource. La valeur etag est modifiée après chaque requête de mutation. Par conséquent, vous obtenez la valeur actuelle du paramètre etag en exécutant une requête GET sur la ressource avant d'effectuer celle pour la mettre à jour.

En utilisant les mappages d'entrée, vous pouvez indiquer à Deployment Manager de récupérer la valeur du champ etag dans la ressource de l'API. Deployment Manager exécute automatiquement une requête GET pour obtenir cette valeur lorsqu'un utilisateur appelle la méthode spécifiée dans les mappages d'entrée.

Simplifier les entrées utilisateur

Deployment Manager gère les propriétés virtuelles, c'est-à-dire les propriétés arbitraires que vous pouvez exposer à vos utilisateurs via Deployment Manager pour différentes utilisations. Les propriétés virtuelles ne sont pas traitées en tant que propriétés sur l'API sous-jacente. Les propriétés virtuelles sont des variables arbitraires dont la valeur peut être injectée si nécessaire dans les mappages d'entrée. Par exemple, supposons qu'une propriété d'API doive être encodée en base64 avant que la valeur ne soit envoyée à l'API sous-jacente. Plutôt que de demander à vos utilisateurs de fournir la valeur avec un encodage en base64, vous pouvez créer une propriété virtuelle leur permettant de saisir la valeur en texte brut, encoder la valeur au format base64 avec des mappages d'entrée, puis fournir le résultat à l'API sous-jacente.

Définir des options avancées

Pour définir des options avancées, fournissez la propriété collectionOverrides lors de la création de votre ressource de fournisseur de types et spécifiez les mappages d'entrée ou les propriétés virtuelles pour chaque collection d'API selon vos besoins.

Par exemple, à l'aide de gcloud CLI, vous pouvez fournir des options avancées à l'aide d'un fichier YAML, puis fournir ce fichier avec votre requête type-providers create. Voici un exemple de fichier YAML :

collectionOverrides:
- collection: /emailAddresses/v1beta/people
  options:
    inputMappings:
    - methodMatch: ^create$
      fieldName: emailAddress.displayName
      value: $.resource.properties.displayName
      location: BODY
    - methodMatch: ^update$
      fieldName: displayName
      value: $.resource.properties.displayName
      location: PATH
    virtualProperties: |
      schema: http://json-schema.org/draft-04/schema#
      type: object
        properties:
          displayName:
            type: string
credential:
  basicAuth:
    user: [USERNAME]
    password: [PASSWORD]

Cette configuration indique à Deployment Manager d'effectuer les opérations suivantes :

  • Pour la méthode create, le champ intitulé emailAddress.displayName doit être recherché dans le corps de la ressource, et la valeur de ce champ doit correspondre à l'entrée de l'utilisateur pour la propriété displayName dans la configuration de Deployment Manager. Par exemple, si un utilisateur définit la configuration comme suit :

     resources:
     - name: example
       type: myproject/emailAddress:/emailAddresses/v1beta/people
       properties:
       - displayName: John Doe
         ...
    

    Deployment Manager définira la valeur du champ emailAddress.displayName sur John Doe.

  • Pour la méthode update, le champ se trouve dans le chemin d'accès de la ressource au lieu du corps de la ressource, mais le même mappage d'entrée doit être appliqué.

Spécifier les mappages d'entrée

Un mappage d'entrée vous permet de mapper ou d'injecter des informations pour certains champs d'API afin que Deployment Manager puisse interagir de manière plus transparente avec l'API sous-jacente. Cela évite ainsi aux utilisateurs de devoir comprendre le comportement subtil de l'API.

Vous pouvez simplifier les interactions de vos utilisateurs avec l'API grâce aux mappages d'entrée. Par exemple, vous pouvez utiliser des mappages d'entrée pour obtenir automatiquement des valeurs générées par le serveur, telles que des empreintes numériques, des ID ou des etags. Cela évite aux utilisateurs d'exécuter une requête get distincte sur la ressource chaque fois qu'ils souhaitent effectuer une mise à jour.

De même, vous pouvez également utiliser des mappages d'entrée pour gérer des scénarios ambigus ou complexes lorsque le même champ d'API présente des valeurs différentes pour plusieurs méthodes. Par exemple, une requête de création de ressource peut nécessiter une propriété name que l'utilisateur peut spécifier, mais la même API peut nécessiter une propriété name dans un format différent pour les méthodes update. Vous pouvez utiliser les mappages d'entrée pour indiquer à Deployment Manager la valeur appropriée pour chaque méthode d'API.

Pour spécifier les mappages d'entrée pour un fournisseur de types, indiquez la propriété options.inputMappings. Vous pouvez définir des mappages d'entrée qui s'appliquent à l'ensemble de l'API ou en fournir explicitement pour chaque collection :

# Input mappings for the entire API
"options": {
  "inputMappings": [
      {
          "fieldName": "[NAME]",
          "location":  "[PATH | BODY | QUERY | HEADER]",
          "methodMatch": "[REGEX_MATCHING_CERTAIN_METHODS]",
          "value": "[VALUE_TO_INJECT]"
      },
      {
          "fieldName": "[NAME]",
          "location":  "[PATH | BODY | QUERY | HEADER]",
          "methodMatch": "[REGEX_MATCHING_CERTAIN_METHODS]",
          "value": "[VALUE_TO_INJECT]"
      }
   ]
},
# Input mappings for specific collections
"collectionOverrides": [
    {
        "collection": "[SPECIFIC_COLLECTION]",
        "options": {
            "inputMappings": [
                {
                    "fieldName": "[NAME]",
                    "location": "[PATH | BODY | QUERY | HEADER]",
                    "methodMatch": "[REGEX_MATCHING_CERTAIN_METHODS]",
                    "value": "[VALUE_TO_INJECT]"
                },
                {
                    "fieldName": "[NAME]",
                    "location": "[PATH | BODY]",
                    "methodMatch": "[REGEX_MATCHING_CERTAIN_METHODS]",
                    "value": "[VALUE_TO_INJECT]"
                },
                ...[additional fields if necessary]...
            ]
        }
    }
]

Chacune des parties importantes de cette syntaxe est décrite ci-dessous.

Collection

La valeur [SPECIFIC_COLLECTION] correspond à la collection d'API pour laquelle ce mappage d'entrée s'applique. Par exemple, si vous fournissez des mappages d'entrées pour un document Google Discovery, comme l'API IAM Service Accounts, les collections pertinentes sont projects.serviceAccounts et projects.serviceAccountKeys.

Pour une API qui utilise la spécification OpenAPI, le chemin de collection peut être /example-collection/{name}. Vous pouvez accéder à un exemple OpenAPI fonctionnel dans le dépôt GitHub OpenAPI.

fieldName

"fieldName" correspond à l'attribut ou à la propriété de l'API pour lesquels vous souhaitez spécifier le mappage d'entrée. Par exemple, "fieldName": "fingerprint", "fieldName": "etag", et ainsi de suite.

Location (Zone)

Les propriétés de l'API peuvent apparaître soit en tant que paramètres dans le chemin de l'URL, soit dans le corps de la requête ou de la réponse. Spécifiez l'emplacement où s'applique le mappage d'entrée, tel que le chemin de l'URL (PATH) ou le corps de la requête (BODY). Les valeurs autorisées incluent les suivantes :

  • PATH
  • BODY
  • QUERY
  • HEADER

methodMatch

Spécifiez les méthodes auxquelles ce mappage d'entrée s'applique. Vous pouvez indiquer plusieurs méthodes à l'aide d'expressions régulières. Exemple :

"methodMatch":"^create$"

Pour la spécification OpenAPI, vous pouvez définir la valeur suivante :

"methodMatch: ^(put|get|delete|post)$"

Valeur

Spécifiez la valeur que Deployment Manager doit injecter pour ce champ. Ce champ utilise le format JSONPath. Par exemple, ce mappage d'entrée indique que Deployment Manager doit utiliser la valeur fournie par l'utilisateur pour le champ name et l'injecter au format projects/$.project/topics/$resource.properties.topic :

"inputMappings":[
{
  "fieldName":"name",
  "location":"PATH",
  "methodMatch":"^post$",
  "value":"concat(\"projects/\", $.project, \"/topics/\", $.resource.properties.topic)"
}...
  • Lorsque vous utilisez $.resource.properties.[VARIABLE], vous spécifiez la valeur d'une propriété qu'un utilisateur définira dans sa configuration. Par exemple, pour $.resource.properties.topic, la valeur correspond à celle fournie par l'utilisateur pour la propriété topic dans sa configuration :

    resources:
    - name: example
      type: example-type-provider:collectionA
      properties:
        topic: history # The value of "history" would be used for the `name` parameter because of the input mapping above
    
  • Pour référencer la ressource elle-même après une requête get, utilisez $.resource.self.[VARIABLE]. Par exemple, pour les requêtes de mise à jour, si vous souhaitez obtenir la dernière empreinte numérique, vous pouvez utiliser la syntaxe suivante pour indiquer à Deployment Manager d'exécuter une commande get et d'en récupérer la valeur :

    {
      'fieldName': 'fingerprint',
      'location': 'BODY',
      'methodMatch': '^(put)$',
      # self represents the resource by doing a GET on it.
      # This mappings gets latest fingerprint on the request.
      # Final PUT Body will be
      # {
      #   "name": "my-resource-name",
      #   "fingerprint": "<server generated fingerprint>"
      # }
      'value': '$.resource.self.fingerprint'
    }
    

Utiliser des propriétés virtuelles

Les propriétés virtuelles sont des propriétés arbitraires que vous pouvez exposer à vos utilisateurs via Deployment Manager. Ces propriétés ne font pas partie de l'API sous-jacente, mais sont des variables arbitraires qui peuvent être utilisées pour transmettre des informations ou masquer les incohérences de l'API à vos utilisateurs. Vous pouvez également référencer des propriétés virtuelles dans vos mappages d'entrée.

Les propriétés virtuelles doivent respecter le schéma JSON 4. Vous pouvez indiquer des propriétés virtuelles dans des éléments options pour une collection spécifique :

"collection": "[SPECIFIC_COLLECTION]",
  "options": {
   "virtualProperties": "schema: http://json-schema.org/draft-04/schema#\ntype: object\nproperties:\n  [PROPERTY]:\n    type: [DATA_TYPE]\n  [ANOTHER_PROPERTY]:\n    type: [ANOTHER_DATA_TYPE]n"
   "inputMappings": [
    ...
   ]
  }

Voici un exemple de propriétés virtuelles dans un fichier de définition YAML :

- collection: projects.serviceAccounts
  options:
    virtualProperties: |
      schema: http://json-schema.org/draft-04/schema#
      type: object
      properties:
        a-property:
          type : string
        b-property:
          type : string
      required:
      - a-property
      - b-property
    inputMappings:
    ...

Prenons l'exemple d'une fausse API qui génère des adresses e-mail. Supposons que l'API dispose d'une méthode pour créer une adresse e-mail en fonction de la valeur de la propriété emailAddress.displayName. Lorsqu'un utilisateur fait une demande de création d'adresse e-mail, la requête se présente comme suit :

POST https://example.com/emailAddresses/v1beta/people/

{
  "emailAddress": {
    "displayName": "john"
  }
}

Supposons maintenant que l'API fournit un moyen de mettre à jour l'adresse e-mail, mais la méthode de mise à jour nécessite uniquement la propriété displayName, plutôt que la propriété email.displayName :

POST https://example.com/emailAddresses/v1beta/people/john

{
  "displayName": "josh"
}

Comment souhaitez-vous que vos utilisateurs fournissent cette valeur lorsqu'ils utilisent ce fournisseur de types ? Vous pouvez leur demander de spécifier la propriété différemment selon l'opération :

# Creating an email
resources:
- name: example-config
  type: projects/test-project:emailAddresses
  properties:
    emailAddress:
      displayName: john

# Updating an email
resources:
- name: example-config
  type: projects/test-project:emailAddresses
  properties:
    displayName: john

Vous pouvez également créer une propriété virtuelle qui utilise la même valeur quelle que soit l'opération, puis utiliser des mappages d'entrée pour mapper la propriété virtuelle au paramètre d'API approprié. Pour cet exemple, supposons que vous avez défini une propriété virtuelle intitulée displayName. Vos mappages d'entrée peuvent alors se présenter comme suit :

{
    "collectionOverrides":[
      {
        "collection":"emailAddresses",
        "options":{
          "inputMappings":[
            {
              "fieldName":"emailAddress.displayName",
              "location":"BODY",
              "methodMatch":"^create$",
              "value":"$.resource.properties.displayName"
            },
            {
              "fieldName":"displayName",
              "location":"BODY",
              "methodMatch":"^update$",
              "value":"$.resource.properties.displayName"
            }
          ],
          "virtualProperties":"schema: http://json-schema.org/draft-04/schema#\ntype: object\nproperties:\n  displayName:\n    type: string\nrequired:\n- displayName\n"
        }
      }
    ],
    "descriptorUrl":"https://example.com/emailAddresses/v1beta/",
    "options":{
      "nameProperty":""
    }
}

Plus précisément, la propriété virtuelle est définie ici :

"virtualProperties":"schema: http://json-schema.org/draft-04/schema#\ntype: object\nproperties:\n  displayName:\n    type: string\nrequired:\n- displayName\n"

En format plus lisible :

"virtualProperties":
  "schema: http://json-schema.org/draft-04/schema#\n
   type: object\n
   properties:\n
     displayName:\n
     - type: string\n
   required:\n
   - displayName\n"

Vos utilisateurs peuvent maintenant spécifier displayName en tant que propriété de premier niveau pour les requêtes de mise à jour et de création, et Deployment Manager saura comment mapper correctement la valeur.

# Creating an email
resources:
- name: example-config
  type: projects/test-project:emailAddresses
  properties:
    displayName: john

# Updating an email
resources:
- name: example-config
  type: projects/test-project:emailAddresses
  properties:
    displayName: john

Étapes suivantes