Configurar opciones de API avanzadas

En esta página se describe cómo establecer opciones de configuración avanzadas, como la asignación de entradas y propiedades virtuales, para proveedores de tipos. Si deseas obtener más información acerca de los tipos, lee la Descripción general de tipos. En caso de que quieras obtener más información sobre proveedores de tipos, consulta la Guía de una página para la integración con Deployment Manager.

Si estás intentando integrar una API que no satisface los requisitos de API definidos por Deployment Manager, puedes utilizar la asignación de entradas y propiedades virtuales a fin de resolver estas incoherencias. Las asignaciones de entradas te permiten proporcionar asignaciones explícitas de parámetros de la API en casos de ambigüedad, y las propiedades virtuales te permiten exponer propiedades arbitrarias que no existen en las API subyacentes, para que puedas simplificar la entrada y ocultar complejidades de la API a tus usuarios.

La implementación de opciones de configuración avanzada requiere estar muy familiarizado con la API para la cual estás creando el proveedor de tipos. Dado que cada API puede variar ampliamente con respecto a otras, esta página ofrece una guía general y ejemplos, pero no proporciona orientaciones específicas de la API.

Antes de comenzar

Situaciones comunes que requieren opciones de configuración avanzada

El nombre de la propiedad se vuelve a usar con diferentes valores

En ciertas API, podría volverse a usar el mismo nombre de propiedad o parámetro 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), podría tener el valor foo/bar, mientras que el mismo campo name de una solicitud de actualización (PATCH o PUT) podría requerir el valor foo/bar/baz.

Los valores de propiedad se pueden inferir de la respuesta de la API

Ciertos métodos de la API requieren un valor generado por el servidor que se muestra cuando realizas una solicitud GET al recurso. Por ejemplo, una API podría requerir un parámetro etag para realizar solicitudes de actualización cuando mute un recurso. El valor etag cambia después de cada solicitud de mutación, por lo que obtienes el parámetro etag actual cuando realizas una solicitud GET al recurso, antes de realizar la solicitud para actualizar el recurso.

Mediante las asignaciones de entrada, puedes indicar a Deployment Manager que el campo etag se puede recuperar del recurso de la API. Deployment Manager realiza una solicitud GET de forma automática a fin de obtener este valor cuando un usuario llama al método que especificaste en las asignaciones de entradas.

Simplifica la entrada del usuario

Deployment Manager es compatible con propiedades virtuales, que son propiedades arbitrarias que puedes exponer a tus usuarios mediante Deployment Manager para diferentes usos. Trata las propiedades virtuales como propiedades que no existen en la API subyacente, sino como variable arbitrarias cuyo valor puedes agregar según sea necesario en las asignaciones de entradas. Por ejemplo, supón que existe una propiedad de la API que debe estar codificada en base64 antes de poder enviar el valor a la API subyacente. En lugar de pedir a los usuarios que proporcionen el valor en la codificación base64, puedes crear una propiedad virtual que solicite a los usuarios el valor de texto sin formato, luego, codificar el valor en base64 con asignaciones de entrada y, por último, proporcionar el resultado a la API subyacente.

Especifica opciones avanzadas

Si quieres especificar opciones avanzadas, proporciona la propiedad collectionOverrides cuando creas tu recurso de proveedor de tipos y define las asignaciones de entrada o propiedades virtuales para cada grupo de API según lo necesites.

Por ejemplo, con gcloud CLI, puedes proporcionar opciones avanzadas con un archivo YAML y suministrarlo con tu solicitud type-providers create. Un archivo YAML de muestra podría verse de la manera siguiente:

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 le dice lo siguiente a Deployment Manager:

  • Al método create, que busque el campo con el nombre emailAddress.displayName en el cuerpo del recurso y configure el valor del campo en la entrada del usuario para la propiedad displayName en la configuración de Deployment Manager. Si un usuario configura su configuración de esta manera:

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

    Deployment Manager establecerá el valor de emailAddress.displayName en John Doe.

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

Especifica la asignación de entrada

Una asignación de entradas te permite asignar o agregar información para ciertos campos de la API a fin de que Deployment Manager pueda interactuar con mayor facilidad con la API subyacente y aliviar la carga de sus usuarios para comprender el comportamiento sutil de la API.

Usa asignaciones de entrada a fin de simplificar la interacción de tus usuarios con la API. Por ejemplo, puedes usar asignaciones de entrada para obtener valores generados por el servidor de forma automática, como huellas digitales, ID o ETags. Así se evita que los usuarios tengan que realizar una solicitud get por separado en el recurso cada vez que quieren realizar una actualización.

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

Si quieres especificar asignaciones de entrada para un proveedor de tipos, debes proporcionar la propiedad options.inputMappings. Puedes definir las asignaciones de entrada que se aplican a toda la API o puedes proporcionar asignaciones de entradas de manera explícita 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 la API a la que se aplica esta asignación de entrada. Por ejemplo, si proporcionabas asignaciones de entrada para un documento de Google Discovery, como la API de cuentas de servicio IAM, los grupos relevantes son projects.serviceAccounts y projects.serviceAccountKeys.

Para una API que usa la especificación de OpenAPI, la ruta de recopilación puede ser /example-collection/{name}. Puedes explorar un ejemplo de OpenAPI funcional en el repositorio de GitHub de OpenAPI.

Nombre del campo

"fieldName" es el atributo o la propiedad de la API para el que quieres especificar la asignación de entrada. Por ejemplo, "fieldName": "fingerprint", "fieldName": "etag", etcétera.

Ubicación

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

  • PATH
  • BODY
  • QUERY
  • HEADER

Coincidencia por método

Especifica a qué métodos se aplican estas asignaciones de entradas. Utiliza regex para especificar varios métodos. Por ejemplo:

"methodMatch":"^create$"

Para las especificaciones de OpenAPI, puedes hacer lo siguiente:

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

Valor

Especifica el valor que Deployment Manager debería agregar para este campo. En este campo, se usa notación JSONPath. Por ejemplo, esta asignación de entrada indica que, para el campo name, Deployment Manager debe tomar el valor suministrado por el usuario y, a continuación, 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 usas $.resource.properties.[VARIABLE], se debe configurar el valor en una propiedad que un usuario establecerá en su configuración. Por ejemplo, para $.resource.properties.topic, el valor será el valor suministrado por el usuario de 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
    
  • Si quieres hacer referencia al recurso después de una solicitud get, usa $.resource.self.[VARIABLE]. Por ejemplo, para las solicitudes de actualización, si quieres obtener la última huella digital, puedes usar esta sintaxis para indicar a Deployment Manager que realice get y tome 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'
    }
    

Usa propiedades virtuales

Las propiedades virtuales son propiedades arbitrarias que puedes exponer a tus usuarios mediante Deployment Manager. Estas propiedades no forman parte de la API subyacente, sino que son variables arbitrarias que pueden usarse a fin de enviar información o, también, ocultar inconsistencias de la API a tus 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 de options para 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, esto se vería de la manera siguiente:

- 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, considera una API falsa que genera direcciones de correo electrónico. Supongamos que la API tiene un método para crear un correo electrónico que toma una propiedad emailAddress.displayName. Cuando un usuario realiza una solicitud para crear una dirección de correo electrónico, se proporciona una solicitud como la que se proporciona a continuación:

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

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

Ahora, supongamos que la API expone una forma de actualizar la dirección de correo electrónico, pero el método para actualizarlo 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 proporcionen este valor cuando usen este tipo de proveedor? Les podrías solicitar que especifiquen la propiedad de manera 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

Por otro lado, puedes crear una propiedad virtual que tome el mismo valor, sin importar la operación y, entonces, usar la asignación de entradas a fin de asignar la propiedad virtual al parámetro correcto de la API. Para este ejemplo, supongamos que definiste una propiedad virtual llamada displayName. Entonces, tus asignaciones de entrada se verían de la manera siguiente:

{
    "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 especial, 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 un formato legible:

"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, tus usuarios pueden especificar displayName como la propiedad de nivel superior para solicitudes de actualización y de creación, y Deployment Manager sabrá cómo asignar el valor de forma correcta.

# 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

¿Qué sigue?