Fazer upload de imagens com a API Publishing dos serviços relacionados a jogos do Google Play

A API Play Games Services Publishing permite fazer upload de uma imagem para um recurso do jogo.

Opções de upload

A API Publishing dos serviços relacionados a jogos do Google Play permite fazer o upload de determinados tipos de dados binários ou mídia. As características específicas dos dados que podem ser enviados por upload são descritas na página de referência de qualquer método que ofereça suporte a uploads de mídia:

  • Tamanho máximo do arquivo para upload: a quantidade máxima de dados que pode ser armazenada com esse método.

  • Tipos MIME de mídia permitidos: os tipos de dados binários que podem ser armazenados usando esse método.

É possível fazer solicitações de upload de qualquer uma das maneiras a seguir. Especifique o método que você está usando com o parâmetro de solicitação uploadType.

  • Upload simples: uploadType=media. para transferências rápidas de arquivos menores, de até 5 MB.

  • Upload de várias partes: uploadType=multipart. Para transferências rápidas de arquivos menores e metadados. O arquivo é transferido com os metadados que o descrevem em uma única solicitação.

  • Upload retomável: uploadType=resumable. Essa é uma opção para um transferência confiável, especialmente de arquivos maiores. Com esse método, você usa uma solicitação de início de sessão, que pode incluir metadados. Essa é uma boa estratégia a ser usada na maioria dos aplicativos, já que também funciona com arquivos menores. Para isso, é necessário fazer uma solicitação HTTP extra por upload.

Ao fazer upload de mídia, você usa um URI especial. Na verdade, os métodos compatíveis com uploads de mídia têm dois endpoints de URI:

  • O URI "/upload", para a mídia. O formato do endpoint de upload é o URI de recurso padrão com um prefixo "/upload". Use esse URI ao transferir os dados de mídia.

    Exemplo: POST /upload/games/v1configuration/images/resourceId/imageType/imageType

  • O URI de recurso padrão, para os metadados. Se o recurso contiver campos de dados, eles serão usados para armazenar os metadados de descrição do arquivo enviado por upload. É possível usar esse URI ao criar ou atualizar valores de metadados.

    Exemplo: POST /games/v1configuration/images/resourceId/imageType/imageType

Upload simples

O método mais fácil de enviar um arquivo é criar uma solicitação de upload simples. Essa é uma boa escolha quando uma das opções a seguir é verdadeira:

  • o arquivo é pequeno o suficiente para que o upload possa ser refeito inteiramente se a conexão falhar;

  • não há metadados para enviar. Isso pode ocorrer quando você planeja enviar os metadados desse recurso em outra solicitação ou caso nenhum metadado tenha suporte nem esteja disponível. Para usar o upload simples, faça uma solicitação POST ou PUT para o URI /upload do método e adicione o parâmetro de consulta uploadType=media. Por exemplo:

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=media

Os cabeçalhos de HTTP que podem ser usados na solicitação do upload simples incluem:

  • Content-Type. Defina conforme um dos tipos permitidos dos dados de mídia do método para upload, especificado na referência da API Publishing.

  • Content-Length. Defina conforme o número de bytes do upload. Não é exigido em caso de uso da codificação de transferência fragmentada.

Exemplo: upload simples

O exemplo a seguir mostra o uso de uma solicitação de upload simples para a API Publishing dos serviços relacionados a jogos do Google Play.

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=media HTTP/1.1
Host: www.googleapis.com
Content-Type: image/png
Content-Length: number_of_bytes_in_file
Authorization: Bearer your_auth_token

PNG data

Se a solicitação for bem-sucedida, o servidor vai retornar o código de status HTTP 200 OK com todos os metadados. Por exemplo:

HTTP/1.1 200
Content-Type: application/json

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

Upload de várias partes

Se você tiver metadados que pretende enviar com os dados de upload, vai poder fazer uma única solicitação multipart/related. Essa é uma boa opção quando os dados que você está enviando são pequenos o bastante para serem enviados novamente por completo em caso de falha da conexão.

Para usar o upload em várias partes, crie uma solicitação POST ou PUT para o URI /upload do método e adicione o parâmetro de consulta uploadType=multipart. Por exemplo:

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=multipart

Os cabeçalhos de HTTP de alto nível que podem ser usados na solicitação de upload de várias partes incluem:

Content-Type. Defina como "multipart/related" e inclua a string limite que você usa para identificar as partes da solicitação.

Content-Length. Defina como o número total de bytes no corpo da solicitação. A parte de mídia da solicitação precisa ser menor que o tamanho máximo de arquivo especificado para este método.

O corpo da solicitação é formatado como um tipo de conteúdo relacionado a várias partes RFC2387 e contém exatamente duas partes. As partes são identificadas por uma string limite e a última string limite é seguida por dois hifens.

Cada parte da solicitação de várias partes precisa de um cabeçalho Content-Type extra:

  • Parte de metadados: precisa vir primeiro, e Content-Type precisa corresponder a um dos formatos de metadados aceitos.

  • Parte de mídia: precisa vir depois, e Content-Type precisa corresponder a um dos tipos MIME de mídia aceitos pelo método.

Consulte a referência da API Publishing da lista de tipos MIME de mídia permitidos e de limites de tamanho de cada método em relação aos arquivos enviados por upload.

Exemplo: upload de várias partes

O exemplo abaixo mostra uma solicitação de upload de várias partes para a API Publishing dos serviços relacionados a jogos do Google Play.

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=multipart HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Type: multipart/related; boundary=foo_bar_baz
Content-Length: number_of_bytes_in_entire_request_body

--foo_bar_baz
Content-Type: application/json; charset=UTF-8

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

--foo_bar_baz
Content-Type: image/png

PNG data
--foo_bar_baz--

Se a solicitação for bem-sucedida, o servidor vai retornar o código de status HTTP 200 OK com todos os metadados:

HTTP/1.1 200
Content-Type: application/json

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

Upload retomável

Para transferir arquivos de dados de maneira mais confiável, use o protocolo de upload retomável. Esse protocolo permite retomar uma operação de upload quando uma falha de comunicação interrompe o fluxo de dados. É especialmente útil no envio de arquivos grandes e na probabilidade de uma interrupção de rede ou outra falha de transmissão ser alta, por exemplo, ao fazer upload de um app cliente para dispositivos móveis. Também é possível reduzir o uso da largura de banda em caso de falhas de rede, e não é necessário reiniciar os uploads de arquivos grandes desde o começo.

As instruções para usar o upload retomável incluem o seguinte:

  1. Iniciar uma sessão retomável. Faça uma solicitação inicial ao URI de upload que inclua os metadados, se houver.

  2. Salve o URI da sessão retomável. Salve o URI de sessão retornado na resposta da solicitação inicial. Ele será usado nas outras solicitações da sessão. Enviar o arquivo.

  3. Envie o arquivo de mídia ao URI de sessão retomável.

Além disso, os apps que usam o upload retomável precisam ter o código para retomar um upload interrompido. Se um upload for interrompido, descubra a quantidade de dados que foi recebida e retome-o daquele ponto.

Iniciar uma sessão retomável

Para iniciar um upload retomável, faça uma solicitação POST ou PUT para o URI /upload do método e adicione o parâmetro de consulta uploadType=resumable. Por exemplo:

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable

Para essa solicitação inicial, o corpo está vazio ou contém somente os metadados. Você transfere o conteúdo real do arquivo que quer enviar por upload nas próximas solicitações.

Use os seguintes cabeçalhos HTTP com a solicitação inicial:

  • X-Upload-Content-Type. Defina de acordo com o tipo MIME de mídia dos dados para upload que serão transferidos nas próximas solicitações.

  • X-Upload-Content-Length. Definido conforme o número de bytes dos dados para upload que serão transferidos nas solicitações subsequentes. Se o tamanho não é conhecido no momento da solicitação, é possível omitir esse cabeçalho.

  • Se estiver fornecendo metadados: Content-Type. Defina de acordo com o tipo dos metadados.

  • Content-Length. Defina conforme o número de bytes fornecidos no corpo dessa solicitação inicial. Não é exigido em caso de uso da codificação de transferência fragmentada.

Consulte a referência da API Publishing da lista de tipos MIME de mídia permitidos e de limites de tamanho de cada método em relação aos arquivos enviados por upload.

Exemplo: solicitação de início de sessão retomável

O exemplo a seguir mostra como iniciar uma sessão retomável para a API Publishing dos serviços relacionados a jogos do Google Play.

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/png
X-Upload-Content-Length: 2000000

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

A próxima seção descreve como processar a resposta.

Salvar o URI da sessão retomável

Se a solicitação de início da sessão for bem-sucedida, o servidor da API vai responder com um código de status HTTP 200 OK. Além disso, ele fornece um cabeçalho Location que especifica o URI da sessão retomável. O cabeçalho Location, mostrado no exemplo abaixo, inclui uma parte do parâmetro de consulta upload_id que fornece o ID de upload exclusivo a ser usado para essa sessão.

Exemplo: resposta de iniciação da sessão retomável

Aqui está a resposta à solicitação realizada na Etapa 1:

HTTP/1.1 200 OK
Location: https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2
Content-Length: 0

O valor do cabeçalho Location, como mostrado na resposta de exemplo acima, é o URI de sessão que você vai usar como endpoint HTTP para realizar o upload real do arquivo ou consultar o status do upload.

Copie e salve o URI da sessão para poder usá-lo nas solicitações subsequentes.

Fazer upload do arquivo

Para fazer upload do arquivo, envie uma solicitação PUT ao URI de upload recebido na etapa anterior. O formato da solicitação de upload é:

PUT session_uri

Os cabeçalhos HTTP a serem usados ao fazer as solicitações de upload retomável de arquivos incluem Content-Length. Defina essa opção conforme o número de bytes incluídos no upload dessa solicitação, que geralmente corresponde ao tamanho do arquivo de upload.

Exemplo: solicitação de upload de arquivo retomável

Esta é uma solicitação retomável para fazer upload de todo o arquivo PNG de 2 milhões de bytes do exemplo atual.

PUT https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1
Content-Length: 2000000
Content-Type: image/png

bytes 0-1999999

Se a solicitação for bem-sucedida, o servidor vai responder com um HTTP 201 Created e todos os metadados associados a esse recurso. Se a solicitação inicial da sessão retomável tivesse sido PUT para atualizar um recurso já existente, a resposta correta seria 200 OK, com todos os metadados associados ao recurso.

Se a solicitação de upload for interrompida ou se você receber uma resposta HTTP 503 Service Unavailable ou qualquer outra 5xx do servidor, siga o procedimento descrito em Retomar um upload interrompido.


Fazer upload do arquivo em partes

Com os uploads retomáveis, é possível dividir um arquivo em fragmentos e enviar diversas solicitações para transferir cada um deles em sequência. Esse não é o método preferido, já que existem custos de desempenho associados às solicitações adicionais que geralmente não são necessários. No entanto, talvez seja necessário usar a divisão em partes para reduzir a quantidade de dados transferidos em uma solicitação única. Isso é útil quando há um limite de tempo fixo para solicitações individuais, como acontece para determinadas classes de solicitações do Google App Engine. Essa opção também permite dar indicações sobre o andamento do upload para navegadores legados que, por padrão, não disponibilizam essa informação.

Se você estiver fazendo upload dos dados em partes, o cabeçalho Content-Range também será obrigatório, com o cabeçalho Content-Length obrigatório para uploads de arquivos completos:

  • Content-Length. Defina conforme o tamanho do fragmento ou possivelmente menor, como ocorre com a última solicitação.

  • Content-Range. Defina para mostrar de quais bytes no arquivo você está fazendo upload. Por exemplo, Content-Range: bytes 0-524287/2000000 mostra que você está fornecendo os primeiros 524.288 bytes (256 x 1.024 x 2) em um arquivo de 2 milhões de bytes.

Exemplo: solicitação de upload de arquivo em partes retomável

Uma solicitação que envia os primeiros 524.288 bytes pode ter esta aparência:

PUT {session_uri} HTTP/1.1
Host: www.googleapis.com
Content-Length: 524288
Content-Type: image/png
Content-Range: bytes 0-524287/2000000

bytes 0-524288

Se a solicitação for bem-sucedida, o servidor vai responder com 308 Resume Incomplete, bem como um cabeçalho Range que identifica o número total de bytes armazenados até o momento:

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-524287

Use o valor superior retornado no cabeçalho Range para determinar onde iniciar a próxima parte. Continue a usar PUT em cada fragmento do arquivo até que tenha sido feito upload dele inteiro.

Se a solicitação PUT de qualquer fragmento for interrompida ou você receber do servidor uma resposta HTTP 503 Service Unavailable ou outra do tipo 5xx, siga o procedimento descrito em Retomar um upload interrompido. No entanto, continue fazendo upload dos fragmentos a partir desse ponto, em vez de enviar todo o resto do arquivo.

Observações importantes:

  • Use o cabeçalho Range na resposta para determinar onde iniciar a próxima parte. Não suponha que o servidor recebeu todos os bytes enviados na solicitação anterior.

  • Cada URI de upload tem validade limitada e expira dentro de um ou dois dias se não for usado. Por essa razão, é recomendável iniciar um upload retomável assim que você tiver o URI de upload e retomar um upload logo após a interrupção.

  • Se você enviar uma solicitação com um ID de sessão de upload expirado, o servidor vai retornar um código de status 404 Not Found. Quando ocorre um erro irrecuperável na sessão de upload, o servidor retorna um código de status 410 Gone. Nesse caso, é necessário iniciar um novo upload retomável, ter um novo URI de upload e iniciar o upload desde o início usando o novo endpoint.

Quando o upload do arquivo inteiro for concluído, o servidor vai responder com um HTTP 201 Created e todos os metadados associados a esse recurso. Se essa solicitação estivesse atualizando uma entidade já existente em vez de criar uma nova, o código de resposta HTTP referente a um upload concluído seria 200 OK.


Retomar um upload interrompido

Se uma solicitação de upload for encerrada antes de receber uma resposta ou você receber uma resposta HTTP HTTP 503 Service Unavailable do servidor, será preciso retomar o upload interrompido. Para retomar um upload interrompido, faça o seguinte:

  1. Solicite o status Consulte o status atual do upload enviando uma solicitação PUT vazia para o URI de upload. Para essa solicitação, os cabeçalhos HTTP precisam incluir um cabeçalho Content-Range indicando que a posição atual no arquivo é desconhecida. Por exemplo, defina Content-Range como */2000000 se o comprimento total do arquivo for de 2 milhões. Se você não souber o tamanho total do arquivo, defina o Content-Range como */*.

  2. Descubra o número de bytes transferidos por upload. Processe a resposta da consulta de status. O servidor usa o cabeçalho Range na resposta para especificar quais bytes foram recebidos até o momento. Por exemplo, um cabeçalho Range de 0-299999 indica que os primeiros 300 mil bytes do arquivo foram recebidos.

  3. Faça upload dos dados restantes. Agora que você sabe em que ponto retomar a solicitação, envie os dados restantes ou o fragmento atual. Nos dois casos, trate os dados restantes como um fragmento separado. Será necessário enviar o cabeçalho Content-Range ao retomar o upload.

Exemplo: retomar um upload interrompido

  1. Solicite o status de upload. A seguinte solicitação usa o cabeçalho Content-Range para indicar que a posição atual no arquivo de 2 milhões de bytes é desconhecida.

    PUT {session_uri} HTTP/1.1
    Content-Length: 0
    Content-Range: bytes */2000000
    
  2. Extraia da resposta o número de bytes enviados por upload até o momento. A resposta do servidor usa o cabeçalho Range para indicar que ele recebeu os primeiros 43 bytes do arquivo até o momento. Use o valor superior do cabeçalho Range para determinar onde iniciar o upload retomado.

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: 0-42
  1. Retome o upload do ponto onde parou. A solicitação a seguir retoma o upload enviando os bytes restantes do arquivo a partir do byte 43.
PUT {session_uri} HTTP/1.1
Content-Length: 1999957
Content-Range: bytes 43-1999999/2000000

bytes 43-1999999

Práticas recomendadas

Ao fazer upload de mídia, é interessante conhecer algumas das práticas recomendadas referentes à correção de erros.

  • Retome ou repita os uploads que falharem devido a interrupções na conexão ou a erros 5xx, incluindo:

    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • Use uma estratégia de espera exponencial se algum erro 5xx do servidor for retornado ao retomar ou fazer novas tentativas de solicitações de upload. Esses erros podem ocorrer quando o servidor fica sobrecarregado. A espera exponencial ajuda a aliviar esses tipos de problemas durante períodos de alto volume de solicitações ou tráfego de rede intenso.

  • Outros tipos de solicitações não podem ser tratados por espera exponencial, mas você ainda pode repetir várias delas. Ao tentar realizar novamente essas solicitações, limite o número de tentativas. Por exemplo, seu código pode limitar a dez tentativas ou menos antes que um erro seja relatado.

  • Trate os erros 404 Not Found e 410 Gone ao fazer uploads retomáveis iniciando o upload completo desde o início.

Espera exponencial

A espera exponencial é uma estratégia padrão de tratamento de erros para aplicativos de rede em que o cliente repete periodicamente uma solicitação com falha ao longo de um período crescente. Se um alto volume de solicitações ou um tráfego de rede intenso faz com que o servidor retorne erros, a espera exponencial pode ser uma boa estratégia para tratar esses erros. Por outro lado, não é uma estratégia relevante para lidar com erros não relacionados a volume de rede ou a tempos de resposta, como erros de credenciais de autorização inválidas ou de arquivo não encontrado.

Usada corretamente, a espera exponencial aumenta a eficiência do uso da largura de banda, reduz o número de solicitações necessárias para conseguir uma resposta bem-sucedida e maximiza a capacidade de solicitações em ambientes simultâneos.

O fluxo para implementação da espera exponencial simples é o seguinte:

  1. Faça uma solicitação para a API.
  2. Receba uma resposta HTTP 503, que indica que você precisa repetir a solicitação.
  3. Aguarde um segundo + random_number_milliseconds e envie novamente a solicitação.
  4. Receba uma resposta HTTP 503, que indica que você precisa repetir a solicitação.
  5. Aguarde dois segundos + random_number_milliseconds e envie novamente a solicitação.
  6. Receba uma resposta HTTP 503, que indica que você precisa repetir a solicitação.
  7. Aguarde quatro segundos + random_number_milliseconds e envie novamente a solicitação.
  8. Receba uma resposta HTTP 503 response, que indica que você precisa repetir a solicitação.
  9. Aguarde oito segundos + random_number_milliseconds e envie novamente a solicitação.
  10. Receba uma resposta HTTP 503 response, que indica que você precisa repetir a solicitação.
  11. Aguarde 16 segundos + random_number_milliseconds e envie novamente a solicitação.
  12. Pare. Relate ou registre um erro.

No fluxo acima, "random_number_milliseconds" é um número aleatório de milissegundos inferior ou igual a mil. Esse procedimento é necessário porque a introdução de um pequeno atraso aleatório ajuda a distribuir a carga de maneira mais uniforme e a evitar a possibilidade de sobrecarga do servidor. O valor de "random_number_milliseconds" precisa ser redefinido após cada período de espera.

O algoritmo é definido para terminar quando n é 5. Esse limite impede que os clientes fiquem tentando infinitamente e gera um atraso total de cerca de 32 segundos antes de uma solicitação ser considerada "um erro irrecuperável". Um número máximo maior de tentativas não é um problema, especialmente se um upload longo estiver em andamento. No entanto, use um atraso de repetição aceitável, por exemplo, menos de um minuto.

Guias da biblioteca de cliente da API