Dicas de desempenho

Este documento abrange algumas técnicas que podem ser usadas para melhorar o desempenho do seu aplicativo. Em alguns casos, exemplos de outras APIs ou APIs genéricas são usados para ilustrar as ideias apresentadas. No entanto, os mesmos conceitos se aplicam à Google Analytics API.

Uso de gzip

Um jeito fácil e conveniente de reduzir a largura de banda necessária para cada solicitação é ativar a compactação gzip. Embora isso exija tempo adicional de CPU para descompactar os resultados, a relação com os custos de rede geralmente é vantajosa.

Para receber uma resposta codificada em gzip, é necessário fazer duas coisas: definir um cabeçalho Accept-Encoding e modificar seu user-agent para que tenha a string gzip. Veja um exemplo de cabeçalhos HTTP devidamente formados para permitir a compactação em gzip:

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

Trabalho com recursos parciais

Outra forma de melhorar o desempenho de suas chamadas de API é enviar e receber somente a parte dos dados que interessam a você. Isso permite que o aplicativo evite a transferência, a análise e o armazenamento de campos desnecessários. Dessa forma, o aplicativo utiliza recursos, incluindo rede, CPU e memória, de forma mais eficiente.

Existem dois tipos de solicitações parciais:

  • Resposta parcial: é uma solicitação usada para especificar os campos a serem incluídos na resposta. Use o parâmetro de solicitação fields.
  • Patch: é uma solicitação de atualização usada para enviar somente os campos que você quer alterar. Use o verbo HTTP PATCH.

Veja mais detalhes sobre como fazer solicitações parciais nas seções a seguir.

Resposta parcial

Por padrão, o servidor retorna a representação completa de um recurso após processar as solicitações. Para um melhor desempenho, é possível pedir ao servidor para enviar somente os campos que você realmente precisa e, em vez disso, receber uma resposta parcial.

Para solicitar uma resposta parcial, use o parâmetro de solicitação fields para especificar os campos que devem ser retornados. Esse parâmetro pode ser usado com qualquer solicitação que retorne dados de resposta.

O parâmetro fields afeta somente os dados de resposta, mas não afeta os dados que você precisa enviar, se houver algum. Para reduzir a quantidade de dados que você envia ao alterar recursos, use uma solicitação de patch.

Exemplo

O exemplo a seguir mostra o uso de parâmetros fields com uma API "de demonstração" genérica (fictícia).

Solicitação simples: essa solicitação GET HTTP omite o parâmetro fields e retorna todo o recurso.

https://www.googleapis.com/demo/v1?key=YOUR-API-KEY

Resposta de recurso completo: os dados de recurso completo incluem os seguintes campos, com muitos outros que foram omitidos para fins de resumo.

{
  "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",
    ...
  },
  ...
  ]
}

Solicitação para uma resposta parcial: a solicitação a seguir para esse mesmo recurso usa o parâmetro fields para reduzir significativamente o volume de dados retornados.

https://www.googleapis.com/demo/v1?key=YOUR-API-KEY&fields=kind,items(title,characteristics/length)

Resposta parcial: para a solicitação acima, o servidor retorna uma resposta que contém somente o tipo de informação, junto com uma matriz reduzida de itens, que inclui só informações do título HTML e características de comprimento em cada item.

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

A resposta é um objeto JSON que traz somente os campos selecionados e os objetos pai deles que estão incluídos.

Veja detalhes sobre como formatar o parâmetro fields e mais informações sobre o que exatamente é retornado na resposta.

Resumo da sintaxe do parâmetro fields

O formato do valor do parâmetro de solicitação fields é vagamente baseado na sintaxe XPath. A sintaxe compatível é resumida a seguir, e os exemplos adicionais são fornecidos na seção seguinte.

  • Use uma lista separada por vírgulas para selecionar diversos campos.
  • Use a/b para selecionar um campo b que está aninhado dentro do campo a, use a/b/c para selecionar um campo c aninhado dentro de b.

    Exceção: para respostas da API que usam wrappers "data", em que a resposta é aninhada dentro de um objeto data que se parece com data: { … }, não incluir "data" na especificação fields. A inclusão de um objeto de dados com uma especificação de campos como data/a/b gera um erro. Em vez disso, use a especificação fields, como a/b.

  • Use um subseletor para solicitar um conjunto de subcampos específicos de matrizes ou objetos, colocando as expressões entre parênteses "( )".

    Por exemplo: fields=items(id,author/email) retorna apenas o ID do item e o e-mail do autor para cada elemento da matriz de itens. Você também pode especificar um único subcampo, em que fields=items(id) é equivalente a fields=items/id.

  • Use caracteres coringa em seleções de campo, se necessário.

    Por exemplo: fields=items/pagemap/* seleciona todos os objetos em um mapa de página.

Mais exemplos de utilização do parâmetro fields

Os exemplos abaixo incluem descrições de como o valor do parâmetro fields afeta a resposta.

Observação: tal como acontece com todos os valores de parâmetro de consulta, o valor do parâmetro fields deve ser codificado como URL. Para facilitar a leitura, os exemplos deste documento omitem a codificação.

Identifique os campos que quer retornar ou faça seleções de campo.
O valor do parâmetro de solicitação fields é uma lista de campos separados por vírgulas em que cada campo é especificado em relação à raiz da resposta. Assim, se você executar uma operação de lista, a resposta é um conjunto e geralmente inclui uma matriz de recursos. Se você executar uma operação que retorna um único recurso, os campos serão especificados em relação a esse recurso. Se o campo selecionado for (ou fizer parte de) uma matriz, o servidor retornará a parte selecionada de todos os elementos na matriz.

Veja alguns exemplos no nível da coleção:
Exemplos Efeito
items Retorna todos os elementos na matriz de itens, incluindo todos os campos em cada elemento, mas não outros campos.
etag,items Retorna o campo etag e todos os elementos na matriz de itens.
items/title Retorna somente o campo title para todos os elementos na matriz de itens.

Sempre que um campo aninhado é retornado, a resposta inclui os objetos pai incluídos. Os campos pai não incluem campos filho, a menos que eles também sejam selecionados de forma explícita.
context/facets/label Retorna somente o campo label para todos os membros da matriz facets, que está aninhada sob o objeto context.
items/pagemap/*/title Para cada elemento na matriz de itens, retorna apenas o campo title (se presente) de todos os objetos que são filhos de pagemap.

Veja alguns exemplos no nível do recurso:
Exemplos Efeito
title Retorna o campo title do recurso solicitado.
author/uri Retorna o subcampo uri do objeto author do recurso solicitado.
links/*/href
Retorna o campo href de todos os objetos que são filhos de links.
Solicite somente partes de campos determinados usando subseleções.
Por padrão, se a solicitação especificar determinados campos, o servidor retornará os objetos ou elementos de matriz por completo. É possível especificar uma resposta que inclua apenas alguns subcampos. Para fazer isso, use a sintaxe de subseleção "( )", como no exemplo abaixo.
Exemplo Efeito
items(title,author/uri) Retorna apenas os valores do title e do uri do autor referentes a cada elemento da matriz de itens.

Como tratar respostas parciais

Após um servidor processar uma solicitação válida com o parâmetro de consulta fields, ele enviará de volta um código de status HTTP 200 OK, além dos dados solicitados. Se o parâmetro de consulta fields tiver um erro ou for inválido, o servidor retornará um código de status HTTP 400 Bad Request, com uma mensagem de erro informando o usuário sobre o erro na seleção de campos (por exemplo, "Invalid field selection a/b").

Veja o exemplo da resposta parcial apresentado na seção introdutória acima. A seleção utiliza o parâmetro fields para determinar quais campos serão retornados.

https://www.googleapis.com/demo/v1?key=YOUR-API-KEY&fields=kind,items(title,characteristics/length)

A resposta parcial tem esta aparência:

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

Observação: para APIs compatíveis com parâmetros de consulta para paginação de dados (maxResults e nextPageToken, por exemplo), use esses parâmetros para reduzir os resultados de cada consulta a um tamanho administrável. Caso contrário, os ganhos de desempenho possíveis com a resposta parcial podem não ser realizados.

Patch (atualização parcial)

Você também pode evitar o envio de dados desnecessários ao modificar recursos. Para enviar dados atualizados somente para os campos específicos que você está alterando, utilize o verbo HTTP PATCH. A semântica de patch descrita neste documento é diferente (e mais simples) do que a implementação GData antiga de atualização parcial.

O exemplo resumido abaixo mostra como usar patch reduz o número de dados que você precisa enviar para fazer uma pequena atualização.

Exemplo

Este exemplo mostra uma solicitação patch simples para atualizar apenas o título de um recurso de uma API "de demonstração" genérica (fictícia). O recurso também tem um comentário, um conjunto de características, status e muitos outros campos. No entanto, a solicitação só envia o campo title, pois é o único que está sendo modificado:

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

{
  "title": "New title"
}

Resposta:

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

O servidor retorna um código de status 200 OK, com a representação completa do recurso atualizado. Como apenas o campo title foi incluído na solicitação de patch, esse é o único valor diferente de antes.

Observação: se o parâmetro da resposta parcial, fields, é usado em combinação com o patch, você aumenta ainda mais a eficiência das suas solicitações de atualização. Uma solicitação de patch só reduz o tamanho da solicitação. Uma resposta parcial reduz o tamanho da resposta. Assim, para reduzir a quantidade de dados enviados em ambos os sentidos, use uma solicitação de patch com o parâmetro fields.

Semântica de uma solicitação de patch

O corpo da solicitação patch inclui somente os campos de recurso que você quer modificar. Ao especificar um campo, é necessário adicionar todos os objetos pai incluídos, assim como os pais incluídos retornados com uma resposta parcial. Os dados modificados que você envia são mesclados com os dados do objeto pai, se houver um.

  • Adicionar: para adicionar um campo que ainda não existe, especifique o novo campo e seu valor.
  • Modificar: para alterar o valor de um campo existente, especifique o novo campo e configure-o como o novo valor.
  • Excluir: para excluir um campo, especifique o campo e configure-o como null. Por exemplo, "comment": null. Você também pode excluir um objeto inteiro (se ele for mutável), configurando-o como null. Se você usa a biblioteca de cliente de APIs para Java, utilize Data.NULL_STRING. Para ver detalhes, consulte JSON null.

Observação sobre matrizes: as solicitações de patch que contêm matrizes substituem a matriz existente pela fornecida por você. Não é possível modificar, adicionar ou excluir itens em uma matriz de forma fragmentada.

Como usar patch em um ciclo de leitura-modificação-gravação

Pode ser útil começar recuperando uma resposta parcial com os dados que você quer modificar. Isso é especialmente importante para os recursos que usam ETags, já que você deve obrigatoriamente fornecer o valor ETag atual no cabeçalho HTTP If-Match para atualizar o recurso. Após conseguir os dados, é possível modificar os valores que você quer alterar e enviar a representação parcial modificada de volta com uma solicitação de patch. Veja um exemplo que pressupõe que o recurso de demonstração usa ETags:

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

Esta é a resposta parcial:

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

A seguinte solicitação de patch baseia-se nessa resposta. Conforme mostrado abaixo, ela também usa o parâmetro fields para limitar os dados retornados na resposta de patch:

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. */
  },
}

O servidor responde com um código de status HTTP "200 OK" e a representação parcial do recurso atualizado:

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. */
  }
}

Como construir uma solicitação de patch diretamente

Para algumas solicitações de patch, é necessário baseá-las nos dados recuperados anteriormente. Por exemplo, se você quiser adicionar um item a uma matriz sem perder os elementos existentes da matriz, é necessário conseguir os dados existentes primeiro. Da mesma forma, se uma API usa ETags, é necessário enviar o valor ETag anterior com sua solicitação a fim de atualizar o recurso.

Observação: é possível usar um cabeçalho HTTP If-Match: * para forçar a passagem de um patch quando as ETags estiverem em uso.  Se você fizer isso, não será necessário fazer a leitura antes da gravação.

No entanto, para outras situações, é possível construir a solicitação de patch diretamente, sem antes recuperar os dados existentes. Por exemplo, você pode facilmente configurar uma solicitação de patch que atualiza um campo para um novo valor ou adiciona um novo campo. Veja um exemplo:

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

Com essa solicitação, se o campo de comentário tiver um valor existente, o novo valor o substituirá. Caso contrário, ele ficará definido como o novo valor. De forma semelhante, se houvesse uma característica de volume, seu valor seria substituído. Do contrário, ele seria criado. O campo accuracy, se definido, é removido.

Como tratar a resposta a um patch

Após o processamento de uma solicitação de patch válida, a API retorna um código de resposta HTTP 200 OK com a representação completa do recurso modificado. Se a API usa ETags, o servidor atualiza os valores de ETags quando a solicitação de patch é processada, tal como acontece com PUT.

A solicitação de patch retorna a representação inteira de recursos, a menos que você use o parâmetro fields para reduzir a quantidade de dados que ela retorna.

Se uma solicitação de patch resulta em um novo estado de recurso sintática ou semanticamente inválido, o servidor retorna um código de status HTTP 400 Bad Request ou 422 Unprocessable Entity, e o estado do recurso permanecerá inalterado. Por exemplo, se você tenta excluir o valor de um campo obrigatório, o servidor retorna um erro.

Notação alternativa quando o verbo HTTP PATCH não é compatível

Se seu firewall não permite solicitações HTTP PATCH, faça uma solicitação HTTP POST e defina o cabeçalho de substituição para PATCH, conforme mostrado abaixo:

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

Diferença entre patches e atualizações

Na prática, quando você envia os dados para uma solicitação de atualização que usa o verbo HTTP PUT, só é necessário enviar os campos que são obrigatórios ou opcionais. Se você envia valores para os campos que são definidos pelo servidor, eles são ignorados. Embora isso possa parecer outra maneira de fazer uma atualização parcial, essa abordagem tem algumas limitações. Com as atualizações que usam o verbo HTTP PUT, a solicitação falha se você não fornece os parâmetros necessários, e ela apaga dados definidos previamente se você não fornece parâmetros opcionais.

Por isso, é muito mais seguro usar patch. Você só fornece os dados para os campos que quer alterar, e os campos omitidos não são apagados. A única exceção a essa regra são os elementos repetidos ou matrizes. Se você os omitir, eles ficarão como estão. Se incluir parte deles, o conjunto inteiro será substituído pelo fornecido.