Configurar opciones avanzadas de API

En esta página se describe cómo configurar opciones avanzadas, como las asignaciones de entrada y las propiedades virtuales, para los proveedores de tipos. Para obtener más información sobre los tipos, consulta el artículo Tipos: descripción general. Para obtener más información sobre los proveedores de tipos, consulta la guía de una página para la integración con Deployment Manager.

Si intentas integrar una API que no cumple los requisitos de la API definidos por Deployment Manager, puedes usar asignaciones de entrada y propiedades virtuales para resolver estas incoherencias. Las asignaciones de entrada te permiten proporcionar asignaciones explícitas de parámetros de API cuando hay ambigüedad, y las propiedades virtuales te permiten exponer propiedades arbitrarias que no existen en las APIs subyacentes para que puedas simplificar la entrada y ocultar las complejidades de la API a tus usuarios.

Para implementar opciones de configuración avanzadas, es necesario conocer a fondo la API para la que se está creando el proveedor de tipos. Como cada API puede variar mucho con respecto a las demás, en esta página se ofrecen directrices y ejemplos generales, pero no se proporcionan directrices específicas para cada API.

Antes de empezar

Casos prácticos habituales que requieren opciones de configuración avanzadas

El nombre de la propiedad se reutiliza con valores diferentes

En algunas APIs, el mismo nombre de propiedad o parámetro se puede reutilizar en diferentes métodos, pero con valores distintos. Por ejemplo, una API puede especificar que el parámetro name para crear un recurso (una solicitud POST) puede tener el valor foo/bar, mientras que el mismo campo name para una solicitud de actualización (PATCH o PUT) puede requerir el valor foo/bar/baz.

Los valores de las propiedades se pueden inferir a partir de la respuesta de la API

Algunos métodos de la API requieren un valor generado por el servidor que se devuelve cuando haces una solicitud GET al recurso. Por ejemplo, una API puede requerir un parámetro etag para hacer solicitudes de actualización al modificar un recurso. El valor de etag cambia después de cada solicitud de mutación, por lo que puedes obtener el parámetro etag actual realizando una solicitud GET al recurso antes de hacer la solicitud para actualizarlo.

Con las asignaciones de entrada, puedes indicar a Deployment Manager que el campo etag se puede obtener del recurso de la API. Deployment Manager realiza automáticamente una solicitud GET para obtener este valor cuando un usuario llama al método que ha especificado en las asignaciones de entrada.

Simplificar la introducción de datos por parte del usuario

Deployment Manager admite propiedades virtuales, que son propiedades arbitrarias que puedes exponer a tus usuarios a través de Deployment Manager para diferentes usos. Las propiedades virtuales se tratan como propiedades que no existen en la API subyacente, sino que son variables arbitrarias cuyo valor puede insertar según sea necesario en sus asignaciones de entrada. Por ejemplo, supongamos que hay una propiedad de API que debe estar codificada en base64 antes de que se envíe el valor a la API subyacente. En lugar de pedir a los usuarios que proporcionen el valor en codificación base64, puede crear una propiedad virtual que solicite a los usuarios el valor de texto sin formato, codificar en base64 el valor con asignaciones de entrada y, por último, proporcionar el resultado a la API subyacente.

Especificar opciones avanzadas

Para especificar opciones avanzadas, proporcione la propiedad collectionOverrides al crear el recurso Type Provider y defina las asignaciones de entrada o las propiedades virtuales de cada colección de APIs según sea necesario.

Por ejemplo, con la CLI de gcloud, puedes proporcionar opciones avanzadas mediante un archivo YAML y suministrar el archivo YAML con tu solicitud type-providers create. Un archivo YAML de ejemplo podría tener este aspecto:

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]

Esta configuración indica a Deployment Manager lo siguiente:

  • En el método create, busca el campo emailAddress.displayName en el cuerpo del recurso y asigna a ese campo el valor que el usuario haya introducido para la propiedad displayName en la configuración de Deployment Manager. Por lo tanto, si un usuario configura su archivo de configuración de la siguiente manera:

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

    Deployment Manager asignará el valor "John Doe" a emailAddress.displayName.

  • En el caso del método update, el campo se encuentra en la ruta del recurso en lugar del cuerpo del recurso, pero se aplica la misma asignación de entrada.

Especificar asignaciones de entrada

Una asignación de entrada le permite asignar o insertar información en determinados campos de la API para que Deployment Manager pueda interactuar de forma más fluida con la API subyacente, lo que evita que los usuarios tengan que comprender el comportamiento sutil de la API.

Usa asignaciones de entrada para simplificar la forma en que los usuarios interactúan con la API. Por ejemplo, puedes usar asignaciones de entrada para obtener automáticamente valores generados por el servidor, como huellas digitales, IDs o etags. De esta forma, los usuarios no tienen que enviar una solicitud get independiente al recurso cada vez que quieran hacer una actualización.

Del mismo modo, también puedes usar asignaciones de entrada para gestionar situaciones ambiguas o confusas en las que el mismo campo de la API tiene valores diferentes para distintos métodos. Por ejemplo, una solicitud para crear un recurso puede requerir una propiedad name que el usuario puede especificar, pero la misma API puede requerir una propiedad name en un formato diferente para los métodos update. Puede usar asignaciones de entrada para indicar a Deployment Manager qué valor es adecuado para cada método de API.

Para especificar las asignaciones de entrada de un proveedor de tipos, proporcione la propiedad options.inputMappings. Puedes definir asignaciones de entrada que se apliquen a toda la API o proporcionar asignaciones de entrada explícitas para cada colección:

# 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]...
            ]
        }
    }
]

A continuación se describe cada una de las partes importantes de esta sintaxis.

Colección

[SPECIFIC_COLLECTION] es la colección de APIs a la que se aplica esta asignación de entrada. Por ejemplo, si proporcionaras asignaciones de entrada para un documento de descubrimiento de Google, como la API IAM Service Accounts, las colecciones pertinentes serían projects.serviceAccounts y projects.serviceAccountKeys.

En el caso de una API que utilice la especificación OpenAPI, la ruta de la colección podría ser /example-collection/{name}. Puedes consultar un ejemplo funcional de OpenAPI en el repositorio de GitHub de OpenAPI.

Nombre del campo

"fieldName" es el atributo o la propiedad de la API para los que quieres especificar la asignación de entrada. Por ejemplo, "fieldName": "fingerprint", "fieldName": "etag" y así sucesivamente.

Ubicación

Las propiedades de la API pueden aparecer como parámetros en la ruta de la URL o como parte del cuerpo de la solicitud o de la respuesta. Especifica dónde se aplica esta asignación de entrada, como la URL PATH o la solicitud BODY como ubicación. Entre los valores admitidos se incluyen los siguientes:

  • PATH
  • BODY
  • QUERY
  • HEADER

Método de coincidencia

Especifica a qué métodos se aplica esta asignación de entrada. Usa expresiones regulares para especificar varios métodos. Por ejemplo:

"methodMatch":"^create$"

En el caso de las especificaciones de OpenAPI, puedes hacer lo siguiente:

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

Valor

Especifica el valor que Deployment Manager debe insertar en este campo. Este campo usa la notación JSONPath. Por ejemplo, esta asignación de entrada indica que, en el campo name, Deployment Manager debe tomar el valor proporcionado por el usuario e insertarlo en el formato projects/$.project/topics/$resource.properties.topic:

"inputMappings":[
{
  "fieldName":"name",
  "location":"PATH",
  "methodMatch":"^post$",
  "value":"concat(\"projects/\", $.project, \"/topics/\", $.resource.properties.topic)"
}...
  • Cuando usa $.resource.properties.[VARIABLE], asigna un valor a una propiedad que un usuario definirá en su configuración. Por ejemplo, en el caso de $.resource.properties.topic, el valor será el que haya proporcionado el usuario para la propiedad topic en su configuración:

    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
    
  • Para hacer referencia al recurso en sí después de una solicitud get, usa $.resource.self.[VARIABLE]. Por ejemplo, en las solicitudes de actualización, si quieres obtener la huella digital más reciente, puedes usar esta sintaxis para indicar a Deployment Manager que realice una get y obtenga el valor:

    {
      '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'
    }
    

Usar propiedades virtuales

Las propiedades virtuales son propiedades arbitrarias que puede exponer a sus usuarios a través de Deployment Manager. Estas propiedades no forman parte de la API subyacente, sino que son variables arbitrarias que se pueden usar para transferir información u ocultar incoherencias de la API a los usuarios. También puedes hacer referencia a propiedades virtuales en tus asignaciones de entrada.

Las propiedades virtuales siguen el esquema JSON 4. Proporciona propiedades virtuales como parte del options de una colección específica:

"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": [
    ...
   ]
  }

En un archivo de definición YAML, sería así:

- 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:
    ...

Por ejemplo, supongamos que tienes una API falsa que genera direcciones de correo electrónico. Supongamos que la API tiene un método para crear un correo que recibe una propiedad emailAddress.displayName. Cuando un usuario solicita crear una dirección de correo, proporciona una solicitud como esta:

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

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

Supongamos que la API ofrece una forma de actualizar la dirección de correo, pero el método para actualizar un correo solo requiere la propiedad displayName, en lugar de la propiedad email.displayName:

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

{
  "displayName": "josh"
}

¿Cómo esperas que tus usuarios aporten este valor cuando usen este tipo de proveedor? Puedes pedirles que especifiquen la propiedad de forma diferente en función de la operación:

# 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

También puedes crear una propiedad virtual que tome el mismo valor, independientemente de la operación, y, a continuación, usar asignaciones de entrada para asignar la propiedad virtual al parámetro de API adecuado. En este ejemplo, supongamos que ha definido una propiedad virtual llamada displayName. Las asignaciones de entrada podrían tener este aspecto:

{
    "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":""
    }
}

En concreto, la propiedad virtual se define aquí:

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

En formato legible por humanos:

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

Ahora, los usuarios pueden especificar displayName como propiedad de nivel superior para las solicitudes de actualización y creación, y Deployment Manager sabrá cómo asignar el valor correctamente.

# 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

Siguientes pasos