API Remote para pacotes de serviços legados

O SDK para Java inclui uma biblioteca chamada Remote API que permite que você acesse serviços do App Engine de maneira transparente a partir de qualquer aplicativo Java. Por exemplo, você pode usar a Remote API para acessar um armazenamento de dados de produção a partir de um aplicativo executado em seu computador local. Também é possível usar a Remote API para acessar o armazenamento de dados de um aplicativo do App Engine a partir de um aplicativo do App Engine diferente.

Como configurar a Remote API no servidor

O componente de servidor da Remote API é um servlet Java que faz parte do tempo de execução do App Engine para Java. Esse servlet recebe solicitações do cliente de Remote API, as despacha para o serviço de back-end adequado e depois retorna o resultado da chamada de serviço ao cliente. Para instalar o servlet da API remota, adicione o seguinte a seu web.xml:

<servlet>
  <display-name>Remote API Servlet</display-name>
  <servlet-name>RemoteApiServlet</servlet-name>
  <servlet-class>com.google.apphosting.utils.remoteapi.RemoteApiServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>RemoteApiServlet</servlet-name>
  <url-pattern>/remote_api</url-pattern>
</servlet-mapping>

O servlet retornará um erro se não houver um usuário autenticado ou se ele não for administrador do aplicativo. Por isso, não é necessário configurar outras medidas de segurança. Depois de implantar seu aplicativo com essas configurações, qualquer aplicativo com o cliente da Remote API instalado pode usar os serviços. Isso inclui clientes Python que usam a Remote API Python.

Como configurar a Remote API em um cliente autônomo

Para configurar o componente cliente da API remota para uso em um aplicativo Java, adicione ${SDK_ROOT}/lib/impl/appengine-api.jar e ${SDK_ROOT}/lib/appengine-remote-api.jar ao seu caminho de classe. Em seguida, em seu código, configure e instale a Remote API:

import com.google.appengine.tools.remoteapi.RemoteApiInstaller;
import com.google.appengine.tools.remoteapi.RemoteApiOptions;

// ...
RemoteApiOptions options = new RemoteApiOptions()
    .server("[APP_ID].[REGION_ID].r.appspot.com", 443)
    .useApplicationDefaultCredential();

RemoteApiInstaller installer = new RemoteApiInstaller();
installer.install(options);
// ... all API calls executed remotely
installer.uninstall();

O cliente da Remote API dependerá das credenciais padrão do aplicativo que usam OAuth 2.0.

Para conseguir uma credencial, execute:

gcloud auth application-default login

É fácil se conectar a um aplicativo do App Engine executado localmente no servidor de desenvolvimento:

RemoteApiOptions options = new RemoteApiOptions()
    .server("localhost", 8888) // server name must equal "localhost"
    .useDevelopmentServerCredential();

Veja um aplicativo Java completo que, ao ser executado, insere uma Entidade no armazenamento de dados:

public class RemoteApiExample {

  public static void main(String[] args) throws IOException {
    String serverString = args[0];
    RemoteApiOptions options;
    if (serverString.equals("localhost")) {
      options = new RemoteApiOptions().server(serverString,
        8080).useDevelopmentServerCredential();
    } else {
      options = new RemoteApiOptions().server(serverString,
        443).useApplicationDefaultCredential();
    }
    RemoteApiInstaller installer = new RemoteApiInstaller();
    installer.install(options);
    try {
      DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
      System.out.println("Key of new entity is " + ds.put(new Entity("Hello Remote API!")));
    } finally {
      installer.uninstall();
    }
  }
}

Como configurar a Remote API em um cliente do App Engine

Você também pode usar a Remote API para acessar os serviços de um aplicativo do App Engine a partir de um aplicativo do App Engine diferente. É necessário adicionar ${SDK_ROOT}/lib/appengine-remote-api.jar ao diretório WEB-INF/lib e, no aplicativo cliente do App Engine, configurar e instalar a API Remote como você fez em seu cliente Java independente.

Observe que o RemoteApiInstaller instala somente a Remote API no thread que executa a instalação, portanto, tenha cuidado para não compartilhar instâncias desta classe em outros threads.

Como usar a Remote API com Maven

Para usar o recurso API Remote no projeto Maven, adicione as seguintes dependências ao arquivo pom.xml do projeto:

<dependency>
  <groupId>com.google.appengine</groupId>
  <artifactId>appengine-remote-api</artifactId>
  <version>1.9.64</version>
</dependency>
<dependency>
  <groupId>com.google.appengine</groupId>
  <artifactId>appengine-api-1.0-sdk</artifactId>
  <version>1.9.64</version>
</dependency>

Limitações e práticas recomendadas

O módulo remote_api empenha um grande esforço para garantir que, até onde for possível, ele se comporte exatamente como o armazenamento de dados nativo do App Engine. Em alguns casos, isso significa executar operações de forma menos eficiente, comparado a outra situação. Ao usar o remote_api, lembre-se:

Cada solicitação do armazenamento de dados requer um percurso completo

Como você está acessando o armazenamento de dados por HTTP, há um pouco mais de sobrecarga e latência do que quando você o acessa localmente. Para agilizar as operações e diminuir a carga, limite o número de percursos de ida e volta por meio de operações em lote de "gets" e "puts" e pela busca de lotes de entidades nas consultas. Isso é recomendável não só para o módulo remote_api, mas para o armazenamento de dados em geral, porque uma operação em lote é considerada apenas como uma única operação do Datastore.

Solicitações para uso da cota do remote_api

Como o remote_api opera com HTTP, cada chamada de armazenamento de dados que você faz utiliza cotas para solicitações HTTP, bytes de entrada e saída, além da cota de armazenamento de dados comum esperada. Lembre-se disso se você estiver usando o remote_api para fazer atualizações em massa.

O limite de 1 MB da API se aplica

Assim como ocorre na execução nativa, o limite de 1 MB para solicitações e respostas da API ainda é aplicável. No caso de entidades grandes, é preciso limitar o número de buscas ou inserções por vez para permanecer abaixo desse limite. Infelizmente, isso causa um conflito com os percursos de ida e volta minimizadores. Por isso, a melhor dica é usar os maiores lotes possíveis sem passar pelas limitações de tamanho de solicitação ou resposta. No entanto, isso provavelmente não será problema para a maioria das entidades.

Evite a iteração de consultas

Ao fazer iterações de consultas, o SDK busca entidades do armazenamento de dados em lotes de 20, buscando um novo lote depois de usar os atuais. Como o remote_api precisar buscar cada lote em uma solicitação separada, ele não consegue fazer isso com tanta eficácia. Em vez disso, ele executa uma consulta totalmente nova para cada lote, usando a funcionalidade de deslocamento para se aprofundar ainda mais nos resultados.

Se você souber de quantas entidades precisa, faça a busca inteira em uma solicitação. Isso pode ser feito com a solicitação do número de que você precisa:

Se não souber de quantas entidades precisa, use os cursores para iterar de forma eficiente em grandes conjuntos de resultados. Isso também evita o limite de 1.000 entidades imposto nas consultas normais ao armazenamento de dados:

As transações são menos eficientes

Para implementar as transações por meio do remote_api, as informações são acumuladas em entidades buscadas na transação, além de cópias das entidades que foram inseridas ou excluídas na transação. Quando executada, a transação envia todas essas informações para o servidor do App Engine, em que é necessário buscar novamente todas as entidades usadas na transação, verificar se não foram modificadas e, em seguida, inserir e excluir todas as alterações feitas pela transação e executá-la. Se houver um conflito, o servidor reverterá a transação e notificará o sistema do cliente, que deverá repetir o processo.

Essa abordagem funciona e duplica exatamente o recurso fornecido pelas transações no armazenamento de dados local, mas é ineficiente. Para não ter dúvidas, use as transações onde forem necessárias, mas tente limitar o número e a complexidade das que forem executadas visando a eficiência.