API remota para Java 8

El SDK de Java incluye una biblioteca llamada API remota que te permite acceder a los servicios de App Engine con transparencia desde cualquier aplicación de Java. Por ejemplo, con la API remota puedes acceder a un almacén de datos de producción desde una aplicación que se ejecuta en tu máquina local. También puedes usar la API remota para acceder al almacén de datos de una aplicación de App Engine desde otra aplicación de esa plataforma.

Cómo configurar la API remota en el servidor

El componente de servidor de la API remota es un servlet de Java que forma parte del entorno de ejecución de App Engine para Java. Este servlet recibe solicitudes desde el cliente de la API remota, las envía al servicio de backend apropiado y, después, le devuelve al cliente el resultado de la llamada de servicio. Para instalar el servlet de la API remota, agrega el siguiente código a 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>

El servlet muestra un error si no existe un usuario autenticado o si el usuario autenticado no es un administrador de tu aplicación; por lo tanto, no se necesitan configuraciones de seguridad adicionales. Una vez implementada tu app con esta configuración, cualquier app que tenga instalado el cliente de API remota puede usar sus servicios. Esto incluye a los clientes de Python que usan la API remota de Python.

Cómo configurar la API remota en un cliente independiente

Para configurar el componente cliente de la API remota de modo de usarlo dentro de una aplicación de Java, agrega ${SDK_ROOT}/lib/impl/appengine-api.jar y ${SDK_ROOT}/lib/appengine-remote-api.jar a tu ruta de clase. Después, en el código, instala y configura la API remota:

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

// ...
RemoteApiOptions options = new RemoteApiOptions()
    .server("your_app_id.appspot.com", 443)
    .useApplicationDefaultCredential();

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

El cliente de la API remota empleará las credenciales predeterminadas de la aplicación que usan OAuth 2.0.

Para obtener una credencial, ejecuta el siguiente comando:

gcloud auth application-default login

Puedes conectarte de manera muy sencilla a una aplicación de App Engine que se ejecute localmente en el Servidor de desarrollado:

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

A continuación se incluye una aplicación Java completa que, cuando se ejecuta, inserta una entidad en el almacén de datos:

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();
    }
  }
}

Cómo configurar la API remota en un cliente de App Engine

También puedes usar la API remota para acceder a los servicios de una aplicación de App Engine desde otra aplicación de esa plataforma. Tienes que agregar ${SDK_ROOT}/lib/appengine-remote-api.jar a tu directorio WEB-INF/lib y, después, en tu aplicación cliente de App Engine, instalar y configurar la API remota, tal como hiciste en tu cliente independiente de Java.

Ten en cuenta que RemoteApiInstaller solo instala la API remota en el subproceso que realiza la instalación, así que ten cuidado de no compartir instancias de esta clase entre subprocesos.

Cómo utilizar la API remota con Maven

Para usar la característica de API remota en tu proyecto de Maven, agrega las siguientes dependencias a tu archivo de proyecto pom.xml:

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

Limitaciones y recomendaciones

En el módulo remote_api se toman muchos recaudos para garantizar que, dentro de lo posible, este se comporte exactamente igual que el App Engine Datastore nativo. En algunos casos, eso implica realizar acciones menos eficientes que en otra situación. Cuando se utiliza remote_api, hay que tener en cuenta lo siguiente:

Toda solicitud al almacén de datos necesita un recorrido de ida y vuelta

Debido a que accedes al almacén de datos a través de HTTP, hay un poco más de sobrecarga y latencia que cuando accedes de forma local. Para acelerar el proceso y disminuir la carga, intenta limitar la cantidad de recorridos de ida y vuelta agrupando funciones get y put, y recuperando lotes de entidades a partir de consultas. Este es un buen consejo para remote_api y para el almacén de datos en general, porque cada operación que involucra un lote se considera solo una operación de Datastore.

Las solicitudes a remote_api consumen cuota

Como remote_api funciona a través de HTTP, toda llamada que realizas al almacén de datos consume cuota de solicitudes HTTP, bytes de entrada y de salida, y la cuota habitual del almacén de datos. Tenlo presente si usas remote_api para llevar a cabo actualizaciones en forma masiva.

Se aplican límites de 1 MB a la API

Al igual que cuando se ejecuta de manera nativa, se aplica el límite de 1 MB para las solicitudes y respuestas de la API. Si tus entidades son de gran tamaño, puede que debas limitar el número de operaciones fetch o put simultáneas para mantenerte por debajo de este límite. Lamentablemente, esta recomendación entra en conflicto con la referida a minimizar los recorridos de ida y vuelta; por eso, el mejor consejo es usar lotes del mayor tamaño posible sin sobrepasar las limitaciones de tamaño de las solicitudes o respuestas. De todas formas, es poco probable que esto represente un problema para la mayoría de las entidades.

Evita la iteración en las consultas

Cuando se realizan iteraciones en las consultas, el SDK recupera entidades desde el almacén de datos en lotes de 20, y recupera un lote nuevo cada vez que se agotan las existentes. Como remote_api debe recuperar cada lote mediante una solicitud independiente, no puede hacerlo con gran eficiencia. En cambio, remote_api ejecuta una consulta completamente nueva por cada lote, y usa la funcionalidad de offset para acceder a más resultados.

Si sabes cuántas entidades necesitas, puedes recuperarlas mediante una única solicitud pidiendo esa cantidad.

Si no sabes cuántas entidades querrás, puedes usar cursores para iterar en conjuntos de resultados grandes de forma eficiente. Esto también te permite evitar el límite de 1,000 entidades impuesto sobre las consultas normales del almacén de datos.

Las transacciones son menos eficientes

Para implementar transacciones a través de remote_api, esta acumula información sobre las entidades recuperadas dentro de una transacción, junto con copias de entidades que se ingresaron o borraron dentro de la transacción. Cuando se confirma la transacción, se envía toda esa información al servidor de App Engine, donde se vuelven a recuperar todas las entidades que se utilizaron en la transacción, se verifica que no se hayan modificado y, después, se ingresan y borran todos los cambios que realizó la transacción y se la confirma. Si hay algún conflicto, el servidor revierte la transacción y notifica al cliente, que luego tiene que ejecutar todo el proceso otra vez.

Este método funciona y duplica de manera exacta la funcionalidad provista por las transacciones en el almacén de datos local, pero es bastante ineficiente. Usa transacciones cuando sean necesarias, pero intenta limitar su cantidad y complejidad para lograr una mayor eficiencia.