Mejorar el rendimiento

En este documento se tratan algunas técnicas que puedes usar para mejorar el rendimiento de una aplicación. En algunos casos, se usan ejemplos de otras APIs o APIs genéricas para ilustrar las ideas presentadas. Sin embargo, se pueden aplicar los mismos conceptos a la API de Compute Engine.

Compresión usando gzip

Una forma sencilla y cómoda de reducir el ancho de banda que se necesita en cada solicitud consiste en habilitar la compresión gzip. Aunque este método requiere tiempo de CPU adicional para descomprimir los resultados, la compensación con la reducción de los costes de red normalmente hace que merezca la pena.

Para recibir una respuesta con codificación gzip debes hacer dos cosas: añadir un encabezado Accept-Encoding y modificar el user-agent para que incluya la cadena gzip. A continuación, te mostramos un ejemplo de encabezados HTTP con formato correcto para habilitar la compresión gzip:

Accept-Encoding: gzip
User-Agent: my program (gzip)

Trabajar con recursos parciales

Otra forma de mejorar el rendimiento de las llamadas de API es enviando y recibiendo solo la parte de los datos que te interesen. De este modo, tu aplicación no tendrá que transferir, analizar y almacenar campos innecesarios y podrá utilizar recursos como la red, la CPU y la memoria con más eficacia.

Hay dos tipos de solicitudes parciales:

  • Respuesta parcial: una solicitud en la que se especifican los campos que se deben incluir en la respuesta (usa el parámetro de solicitud fields).
  • Parche: solicitud de actualización en la que solo se envían los campos que se quieren cambiar (se usa el verbo PATCH de HTTP).

En las siguientes secciones se ofrecen más detalles sobre cómo hacer solicitudes parciales.

Respuesta parcial

De forma predeterminada, el servidor muestra la representación completa de un recurso después de procesar las solicitudes. Para lograr el mejor rendimiento, en lugar de eso puedes pedir al servidor que envíe solamente los campos que realmente necesita y obtener una respuesta parcial.

Si quieres solicitar una respuesta parcial, usa el parámetro de solicitud fields para especificar los campos que quieres que se devuelvan. Puedes usar este parámetro con cualquier solicitud que devuelva datos de respuesta.

Tenga en cuenta que el parámetro fields solo afecta a los datos de respuesta. No afecta a los datos que debe enviar, si procede. Para reducir la cantidad de datos que envías al modificar recursos, utiliza una solicitud patch.

Ejemplo

En el siguiente ejemplo se muestra el uso del parámetro fields con una API Demo genérica (ficticia).

Solicitud simple: esta solicitud GET de HTTP omite el parámetro fields y devuelve el recurso completo.

https://www.googleapis.com/demo/v1

Respuesta completa del recurso: entre la información completa del recurso se incluyen los siguientes campos (muchos otros se han omitido por brevedad).

{
  "kind": "demo",
  ...
  "items": [
  {
    "title": "First title",
    "comment": "First comment.",
    "characteristics": {
      "length": "short",
      "accuracy": "high",
      "followers": ["Jo", "Will"],
    },
    "status": "active",
    ...
  },
  {
    "title": "Second title",
    "comment": "Second comment.",
    "characteristics": {
      "length": "long",
      "accuracy": "medium"
      "followers": [ ],
    },
    "status": "pending",
    ...
  },
  ...
  ]
}

Solicitud de una respuesta parcial: la solicitud siguiente de este mismo recurso utiliza el parámetro fields para reducir considerablemente la cantidad de datos devueltos.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

Respuesta parcial: en respuesta a la solicitud anterior, el servidor devuelve una respuesta que contiene solamente información sobre el tipo, junto con una matriz reducida de elementos que solo incluye el título en HTML y la información característica de la longitud en cada elemento.

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

Ten en cuenta que la respuesta es un objeto JSON que incluye solamente los campos seleccionados y los objetos contenedores principales.

A continuación se explican los detalles sobre cómo dar formato al parámetro fields, así como información sobre qué resultados se devuelven exactamente en la respuesta.

Resumen de la sintaxis del parámetro fields

El formato del valor del parámetro de solicitud fields se basa libremente en la sintaxis XPath. A continuación se resume la sintaxis compatible y, en la siguiente sección, se proporcionan más ejemplos:

  • Usa una lista separada por comas para seleccionar varios campos.
  • Usa a/b para seleccionar un campo b que esté anidado en el campo a. Usa a/b/c para seleccionar un campo c anidado en b.

    Excepción: En el caso de las respuestas de APIs que utilizan envoltorios "data", en las que la respuesta está anidada en un objeto data similar a data: { ... }, no incluyas "data" en la especificación fields. Si se incluye un objeto de datos en el que el valor data/a/b se haya especificado como parámetro fields, se producirá un error. En su lugar, como el parámetro fields especifica el valor a/b.

  • Utiliza un subselector para solicitar un conjunto de subcampos específicos de matrices u objetos. Para ello, incluye las expresiones entre paréntesis "( )".

    Por ejemplo, fields=items(id,author/email) devuelve solamente el ID del elemento y el correo electrónico del autor de cada elemento en la matriz de elementos. También puedes especificar un único subcampo, donde fields=items(id) equivale a fields=items/id.

  • Usa comodines en las selecciones de campos, si fuera necesario.

    Por ejemplo, fields=items/pagemap/* selecciona todos los objetos de un mapa de páginas.

Más ejemplos de uso del parámetro fields

En los ejemplos que se muestran a continuación se incluyen las descripciones de cómo afecta el valor del parámetro fields a la respuesta.

Nota: Al igual que ocurre con todos los valores del parámetro de consulta, el valor del parámetro fields debe ser una URL codificada. Para facilitar la lectura, los ejemplos de este documento omiten la codificación.

Identifica los campos que quieras que devuelvan un valor o haz selecciones de campos.
El valor del parámetro de solicitud fields es una lista de campos separados por comas, en la que cada campo se especifica en relación con la raíz de la respuesta. De este modo, si ejecutas una operación de lista, la respuesta es una colección y por lo general incluye una matriz de recursos. Si ejecutas una operación que devuelve un único recurso, se especifican los campos en relación con ese recurso. pero si el campo que selecciona es (o forma parte de) una matriz, el servidor devuelve la parte seleccionada de todos los elementos de la matriz.

A continuación te mostramos algunos ejemplos a nivel de colección:
Ejemplos Efecto
items Devuelve todos los elementos de la matriz de elementos, incluidos todos los campos de cada elemento, pero no el resto de campos.
etag,items Devuelve el campo etag y todos los elementos de la matriz de elementos.
items/title Devuelve solo el campo title de todos los elementos de la matriz de elementos.

Siempre que se devuelve un campo anidado, la respuesta incluye los objetos contenedores principales. Los campos principales no incluyen otros campos secundarios, salvo que también se hayan seleccionado de forma explícita.
context/facets/label Devuelve solo el campo label por todos los miembros de la matriz facets, que está anidada en el objeto context.
items/pagemap/*/title Por cada elemento de la matriz de elementos, devuelve únicamente el campo title (si está) de todos los objetos secundarios de pagemap.

A continuación, te mostramos algunos ejemplos a nivel de recurso:
Ejemplos Efecto
title Devuelve el campo title del recurso solicitado.
author/uri Devuelve el subcampo uri del objeto author del recurso solicitado.
links/*/href
Devuelve el campo href de todos los objetos secundarios de links.
Solicita solamente partes de campos concretos mediante subselecciones.
De forma predeterminada, si en tu solicitud se especifican campos concretos, el servidor devuelve los objetos o los elementos de la matriz en su totalidad. Puedes especificar una respuesta que incluya únicamente determinados subcampos. Puedes hacerlo mediante la sintaxis de selección secundaria "( )", tal como se muestra en el ejemplo siguiente.
Ejemplo Efecto
items(title,author/uri) Devuelve únicamente los valores del title y del uri del autor por cada elemento de la matriz de elementos.

Gestionar respuestas parciales

Después de que un servidor procese una solicitud válida que incluya el parámetro de consulta fields, devuelve un código de estado HTTP 200 OK, junto con los datos solicitados. Si el parámetro de consulta fields presenta un error o no es válido, el servidor devuelve un código de estado 400 Bad Request de HTTP, junto con un mensaje de error que indica qué fallaba en la selección de los campos (por ejemplo, "Invalid field selection a/b").

A continuación, se muestra el ejemplo de respuesta parcial que aparece arriba, en la sección de introducción. La solicitud usa el parámetro fields para especificar qué campos tiene que devolver.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

La respuesta parcial tiene este aspecto:

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

Nota: Con las APIs que admiten parámetros de consulta en la paginación de datos (maxResults y nextPageToken, por ejemplo), utiliza estos parámetros para reducir los resultados de cada consulta de forma que puedan procesarse fácilmente. De lo contrario, podrían no obtenerse los beneficios de rendimiento que se conseguirían con la respuesta parcial.

Parche (actualización parcial)

También puedes evitar enviar datos innecesarios al modificar recursos. Para enviar datos solo de los campos que estás cambiando, utiliza el verbo PATCH de HTTP. La semántica de los parches descrita en este documento es diferente (y más sencilla) que la de la implementación anterior de GData para la actualización parcial.

En el breve ejemplo que se ofrece a continuación se muestra cómo el uso de parches minimiza los datos necesarios que se deben enviar para hacer una pequeña actualización.

Ejemplo

En este ejemplo se muestra una solicitud de parche sencilla para actualizar solo el título de un recurso de API "Demo" genérico (ficticio). El recurso también tiene un comentario, un conjunto de características, un estado y muchos otros campos, pero esta solicitud solo envía el campo title, ya que es el único que se modifica:

PATCH https://www.googleapis.com/demo/v1/324
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "title": "New title"
}

Respuesta:

200 OK
{
  "title": "New title",
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "accuracy": "high",
    "followers": ["Jo", "Will"],
  },
  "status": "active",
  ...
}

El servidor devuelve un código de estado 200 OK junto con la representación completa del recurso actualizado. Como solo se ha incluido el campo title en la solicitud de parche, es el único valor que ha cambiado.

Nota: Si usas el parámetro respuesta parcial fields junto con el método PATCH, puedes aumentar aún más la eficiencia de tus solicitudes de actualización. Una solicitud de parche solo reduce el tamaño de la solicitud. Una respuesta parcial reduce el tamaño de la respuesta. Por lo tanto, para reducir la cantidad de datos enviados en ambas direcciones, usa una solicitud PATCH con el parámetro fields.

Semántica de una solicitud PATCH

El cuerpo de la solicitud PATCH solo incluye los campos de recursos que quieras modificar. Cuando especifiques un campo, debes incluir los objetos contenedores principales, al igual que se devuelven los contenedores principales con una respuesta parcial. Los datos modificados que envíes se fusionan con los datos del objeto principal, si hay alguno.

  • Añadir: para añadir un campo que no exista todavía, especifícalo junto con su valor.
  • Modificar: para cambiar el valor de un campo, especifícalo y asigna el nuevo valor.
  • Eliminar: para eliminar un campo, especifícalo y configúralo como null. Por ejemplo, "comment": null. También puedes eliminar un objeto entero que sea mutable eligiendo el valor null. Sin embargo, si estás usando la biblioteca de cliente de la API de Java, utiliza Data.NULL_STRING. Para obtener más información al respecto, consulta JSON null.

Nota sobre las matrices: Las solicitudes PATCH que contienen matrices sustituyen la matriz actual por la que proporciones. No puedes cambiar, añadir ni eliminar elementos de una matriz de forma gradual.

Usar el parche en un ciclo de lectura, modificación y escritura

Es recomendable empezar recuperando una respuesta parcial con los datos que quieras modificar. Este método es de gran importancia en el caso de los recursos que utilizan ETags, ya que debes especificar el valor ETag actual en el encabezado HTTP If-Match para actualizar el recurso correctamente. Después de obtener los datos, puedes modificar los valores que quieras cambiar y enviar la representación parcial modificada con una solicitud de parche. A continuación, te presentamos un ejemplo en el que se supone que el recurso Demo utiliza ETag:

GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token

Esta es la respuesta parcial:

200 OK
{
  "etag": "ETagString"
  "title": "New title"
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "level": "5",
    "followers": ["Jo", "Will"],
  }
}

La siguiente solicitud PATCH se basa en esa respuesta. Como se muestra a continuación, también usa el parámetro fields para limitar los datos devueltos en la respuesta del parche:

PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json
If-Match: "ETagString"
{
  "etag": "ETagString"
  "title": "",                  /* Clear the value of the title by setting it to the empty string. */
  "comment": null,              /* Delete the comment by replacing its value with null. */
  "characteristics": {
    "length": "short",
    "level": "10",              /* Modify the level value. */
    "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */
    "accuracy": "high"          /* Add a new characteristic. */
  },
}

El servidor responde con un código de estado HTTP 200 OK y la representación parcial del recurso actualizado:

200 OK
{
  "etag": "newETagString"
  "title": "",                 /* Title is cleared; deleted comment field is missing. */
  "characteristics": {
    "length": "short",
    "level": "10",             /* Value is updated.*/
    "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */
    "accuracy": "high"         /* New characteristic is present. */
  }
}

Crear una solicitud de parche directamente

Algunas solicitudes de parche hay que basarlas en los datos que se han recuperado anteriormente. Por ejemplo, si quieres añadir un elemento a una matriz y no quieres perder ninguno de los elementos que dicha matriz tenga, primero debes obtener los datos que contiene en ese momento. Del mismo modo, si una API utiliza ETags, debes enviar el valor ETag anterior con la solicitud para actualizar el recurso correctamente.

Nota: Puedes utilizar un encabezado HTTP "If-Match: *" para forzar que se realice un parche cuando se usan valores ETag.  Si lo haces de esta forma, no necesitas hacer la operación de lectura antes de la de escritura.

Sin embargo, en otras situaciones, puede crear la solicitud de parche directamente, sin recuperar primero los datos. Por ejemplo, puedes configurar una solicitud de parche que actualice un campo con un valor nuevo o que añada un campo nuevo. A continuación se muestra un ejemplo:

PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "comment": "A new comment",
  "characteristics": {
    "volume": "loud",
    "accuracy": null
  }
}

En esta solicitud, si el campo comment ya tiene un valor, el nuevo valor sobrescribe este último; de lo contrario, lo configura como el nuevo valor. Del mismo modo, si hay una característica volume, su valor se sobrescribe, y de lo contrario, se crea. Si se ha definido, se elimina el campo de precisión.

Gestionar la respuesta a un parche

Después de procesar una solicitud de parche válida, la API devuelve un código de respuesta HTTP 200 OK junto con la representación completa del recurso modificado. Si la API usa ETag, el servidor actualiza los valores ETag cuando procesa correctamente una solicitud de parche, al igual que con PUT.

La solicitud de parche devuelve la representación completa del recurso, a menos que uses el parámetro fields para reducir la cantidad de datos que devuelve.

Si una solicitud de parche da como resultado un nuevo estado de recurso que no es válido sintáctica ni semánticamente, el servidor devuelve el código de estado HTTP 400 Bad Request o 422 Unprocessable Entity, y no se modifica el estado del recurso. Por ejemplo, si intentas eliminar el valor de un campo obligatorio, el servidor devuelve un error.

Notación alternativa cuando no se admite el verbo HTTP PATCH

Si tu firewall no permite las solicitudes PATCH de HTTP, haz una solicitud POST de HTTP y configura el encabezado de anulación como PATCH, tal como se muestra a continuación:

POST https://www.googleapis.com/...
X-HTTP-Method-Override: PATCH
...

Diferencia entre parche y actualización

En la práctica, cuando envías datos de una solicitud de actualización que utiliza el verbo PUT de HTTP, solo tienes que enviar los campos que son obligatorios u opcionales; si envías valores que configura el servidor, se ignoran. Aunque pueda parecer otra forma de hacer una actualización parcial, este método tiene algunas limitaciones. En las actualizaciones que usan el verbo PUT de HTTP, la solicitud falla si no proporcionas los parámetros obligatorios y se borran los datos definidos anteriormente si no proporcionas los parámetros opcionales.

Por este motivo, es mucho más seguro usar un parche. Solo debe proporcionar datos de los campos que quiera cambiar. Los campos que omita no se borrarán. La única excepción a esta regla se produce al repetir elementos o matrices. Si omites todos los campos, se quedan como estaban; sin embargo, si proporcionas alguno, el conjunto completo se reemplaza por el que has proporcionado.