En este artículo se muestra cómo conectar App Engine a Firebase y, a continuación, utilizar Firebase para enviar actualizaciones en tiempo real en un juego interactivo multijugador de tres en línea. Puedes obtener el código de muestra en el proyecto de tres en línea para Python o Java.
Puedes usar App Engine junto con Firebase Realtime Database para enviar actualizaciones inmediatas al navegador y a los clientes móviles sin una conexión de transmisión persistente con el servidor o un sondeo largo. Esta capacidad es útil para las aplicaciones que brindan actualizaciones a los usuarios sobre información nueva en tiempo real. Los casos prácticos de ejemplo incluyen aplicaciones colaborativas, juegos multijudador y salas de chat.
Usar Firebase es mejor que realizar sondeos cuando las actualizaciones no pueden predecirse o programarse como cuando se retransmite información entre usuarios humanos o cuando los eventos no se generan de manera sistemática.
Este artículo muestra cómo completar las siguientes tareas en el servidor:
- Configura el servidor para utilizar Firebase Realtime Database.
- Crea una referencia de base de datos única de Firebase para cada cliente web que se conecte a tu servicio.
- Envía actualizaciones en tiempo real a los clientes web; para ello, cambia los datos que figuran en una referencia de base de datos particular.
- Mejora la seguridad cuando se acceda a los mensajes; para ello, crea tokens únicos para cada cliente web y utiliza las reglas de seguridad de la base de datos de Firebase.
- Recibe mensajes de los clientes web a través de HTTP.
- Borra los datos del juego de la base de datos después de que haya terminado la partida.
Este artículo también muestra cómo completar las siguientes tareas en el navegador web:
- Conéctate a Firebase con un token único del servidor.
- Actualiza de manera dinámica la interfaz cuando se actualice la referencia de base de datos.
- Envía mensajes de actualización al servidor para que puedan pasarse a clientes remotos.
Comenzar a usar Firebase Realtime Database
Con Firebase Realtime Database, puedes compilar aplicaciones avanzadas y colaborativas, ya que permite el acceso a la base de datos directamente desde el código del cliente. Los datos persisten de forma local. Además, los eventos en tiempo real se siguen activando, incluso sin conexión, lo que proporciona una experiencia adaptable al usuario final. Cuando el dispositivo vuelve a conectarse, Realtime Database sincroniza los cambios de los datos locales con las actualizaciones remotas que ocurrieron mientras el cliente estaba sin conexión, lo que combina los conflictos de forma automática.
Crear un proyecto de Firebase
Crea una cuenta de Firebase o inicia sesión en una cuenta existente.
Haz clic en Agregar proyecto.
Ingresa un nombre en el campo Nombre del proyecto.
Sigue los pasos de configuración restantes y haz clic en Crear proyecto.
Después de que el asistente aprovisione tu proyecto, haz clic en Continuar.
En la página Descripción general de tu proyecto, haz clic en el ícono de ajustes Configuración y, a continuación, haz clic en Configuración del proyecto.
Selecciona la opción Agregar Firebase a tu aplicación web.
Haz una copia del fragmento de código de inicialización, que se requiere en la sección Agregar el SDK de Firebase a tu página web.
Crear Realtime Database
En el menú de la izquierda de Firebase console, selecciona Base de datos en el grupo Desarrollar.
En la página Base de datos, ve a la sección Realtime Database y haz clic en Crear base de datos.
En el cuadro de diálogo Reglas de seguridad para Realtime Database, selecciona Comenzar en modo de prueba y haz clic en Habilitar.
Trabajar con datos en Firebase
Todos los datos de Firebase Realtime Database se almacenan como objetos JSON. La base de datos puede conceptualizarse como un árbol JSON alojado en la nube. A diferencia de una base de datos de SQL, no hay tablas ni registros. Cuando le agregas datos al árbol JSON, estos se convierten en un nodo de la estructura JSON existente con una clave asociada. Puedes proporcionar tus propias claves como ID de usuario o nombres semánticos.
Esta estructura facilita la lectura de datos porque los clientes solo necesitan navegar a una ruta determinada y todo el objeto se muestra en el formato JSON. No se requiere un procesamiento especial de los campos de la base de datos. Para obtener más información, consulta cómo Estructurar tu base de datos en la documentación de Firebase.
Los backends de Java pueden utilizar la API de REST o el SDK de Firebase Admin. Si utilizas el SDK de Firebase Admin para Java en App Engine, asegúrate de usar el entorno de ejecución de Java 8. La versión 6.0.0 y superior del SDK dependen de la compatibilidad para multiprocesos disponible en el entorno de ejecución de Java 8 en App Engine.
Cuando se utiliza la API de REST, Firebase maneja los métodos PUT
, PATCH
, POST
, GET
y DELETE
de HTTP estándar para realizar las operaciones de la base de datos. Para obtener más información sobre cómo utiliza Firebase estas operaciones, consulta Guardar datos y Recuperar datos en la documentación de Firebase.
Escribir datos y enviar mensajes
Para realizar solicitudes autenticadas, las aplicaciones deben obtener las Credenciales predeterminadas de aplicación de App Engine con los alcances necesarios de la autorización y utilizarlas para crear un objeto HTTP. Las solicitudes que se realizan con el objeto HTTP automáticamente incluyen los encabezados Authorization
que se necesitan para realizar solicitudes a Firebase. Para obtener más información sobre las Credenciales predeterminadas de la aplicación, consulta Configurar la autenticación para aplicaciones de producción de servidor a servidor.
Puedes usar el método PUT
de HTTP para escribir o reemplazar datos en una ruta específica de Firebase, como se muestra en el siguiente ejemplo:
Python
...
Java
Para ver implementaciones de muestra en GitHub para PATCH
y POST
, haz clic en el botón Ver en GitHub en el ejemplo de código anterior.
Para leer datos, realiza una solicitud GET
HTTP para una ruta específica. La respuesta contiene el objeto JSON en la ubicación solicitada.
Python
Java
Consulta Hacer una revisión general en la aplicación de muestra para ver ejemplos que utilizan PATCH
y DELETE
.
Detectar eventos en tiempo real desde un navegador web
Para detectar eventos en tiempo real, necesitas:
- Agregar el SDK de Firebase a tu página web
- Agregar una referencia a la ruta de Firebase donde se almacenan los datos
- Agregar un objeto de escucha
- Implementar una función de devolución de llamada
Agregar el SDK de Firebase a tu página web
Para agregar el SDK de Firebase a tu página web:
- Dirígete a tu proyecto en Firebase console.
- Haz clic en Agregar Firebase a tu aplicación web.
Copia el fragmento dado y pégalo en el código HTML. Por ejemplo, en este proyecto de muestra:
Python
Reemplaza el contenido del archivo
templates/_firebase_config.html
con el fragmento. Este archivo se incluye en el archivo de plantilla principalfire_index.html
.Java
Reemplaza el contenido del archivo
src/main/webapp/WEB-INF/view/firebase_config.jspf
con el fragmento. Este archivo se incluye en el archivo de plantilla principalindex.jsp
.
Detectar los cambios en los datos
Para recuperar datos en Firebase, adjunta un objeto de escucha asíncrono a firebase.database.Reference
. El objeto de escucha se activa una vez para el estado inicial de los datos y otra vez cuando los datos cambian. Existen dos tipos de cambios principales que el cliente puede detectar:
- Eventos de valor: lee y detecta los cambios en todo el contenido de una ruta. Por lo general, los eventos de valor se utilizan para supervisar los cambios en un solo objeto.
- Eventos secundarios: lee y detecta los cambios en los elementos secundarios en una ruta específica. Por lo general, los eventos secundarios se utilizan para supervisar los cambios dentro de las listas de objetos. Es posible detectar los siguientes eventos secundarios:
child_added
,child_changed
,child_moved
ychild_removed
.
Esta aplicación de ejemplo mantiene un solo objeto de estado de juego sincronizado entre el servidor y el cliente. Por este motivo, este artículo se centra en la detección de eventos de valor. Los objetos de escucha de eventos secundarios y las técnicas de recuperación de datos más avanzadas se describen en Recuperar datos en la Web.
El siguiente código muestra cómo detectar un evento de cambio de valor y agregar una función de devolución de llamada para realizar el trabajo cuando se activa el evento. El código primero crea una referencia de base de datos, que es la ruta del objeto que detecta la aplicación.
A continuación, se agrega el objeto de escucha a la referencia con el método reference.on()
, en donde la función de devolución de llamada se pasa como un argumento.
En este ejemplo, una aplicación de tres en línea en tiempo real envía información del juego a los clientes que se detectan en canales específicos, que corresponden al juego del usuario, y actualiza la IU cuando esta información cambia en la base de datos. El fragmento de JavaScript que se agregó en Agregar Firebase a tu página web crea automáticamente la variable firebase
.
Python
Java
La implementación de la función de devolución de llamada, onMessage()
, se muestra más adelante en este artículo.
Separar objetos de escucha
Para quitar las devoluciones de llamada, llama al método off()
de tu referencia de base de datos de Firebase.
Publicar eventos de nuevo en App Engine
App Engine no admite actualmente conexiones HTTP de transmisión bidireccional. Si un cliente necesita actualizar el servidor, debe enviar una solicitud HTTP explícita.
Restringir el acceso a tus datos
Firebase te permite restringir el acceso a los datos a usuarios específicos mediante el uso de tokens de autorización. Recomendamos que solo tu servidor tenga acceso de escritura, al tiempo que autoriza a los clientes web para el acceso de solo lectura. El código que figura a continuación muestra cómo:
- Generar credenciales para el servidor de App Engine
- Generar tokens para cada cliente
- Pasar tokens a los clientes web que pueden usar para leer datos
Establecer la comunicación entre App Engine y Firebase
Puedes usar las Credenciales predeterminadas de la aplicación integradas de App Engine para realizar llamadas autenticadas de REST a tu base de datos de Firebase desde el servidor de App Engine.
Python
Crea una instancia para un objeto GoogleCredentials
, que proporciona el paquete oauth2client, con los alcances adecuados para otorgar acceso a Firebase. A continuación, utiliza ese objeto para autorizar un objeto httplib2.Http
.
Ese objeto incluye el token de autenticación adecuado de forma automática, y puedes utilizar el objeto httplib2.Http
directamente para realizar llamadas de REST. La siguiente función utiliza el objeto que se devuelve desde _get_http()
para enviar una solicitud PATCH
o DELETE
. Ten en cuenta que este ejemplo llama a _get_http()
, como parte de la instrucción de devolución, para obtener el objeto HTTP autorizado:
Java
Debido a que App Engine restringe la capacidad de crear conversaciones en segundo plano, debes utilizar la API de Firebase en lugar del SDK del servidor de Firebase directamente.
Primero, obtén las Credenciales predeterminadas de la aplicación y, luego, inicializa el objeto UrlFetchTransport
.
A continuación, utiliza esa credencial para crear un objeto HttpRequestFactory
autorizado, con el uso del servicio de recuperación de URL que App Engine requiere para las solicitudes HTTP de ida. Para realizar llamadas a la base de datos de Firebase, construye una ruta y realiza la solicitud:
Los ejemplos anteriores utilizan la biblioteca httplib2 para Python y la biblioteca cliente HTTP de Google para Java para manejar las solicitudes de REST. Sin embargo, puedes usar el método que prefieras para realizar las solicitudes de REST.
Generar tokens de autenticación de clientes
Firebase utiliza tokens web JSON (JWT) para autorizar a los usuarios. Para crear JWT, la aplicación aprovecha el servicio integrado App Identity de App Engine para firmar las reclamaciones con el uso de las Credenciales predeterminadas de la aplicación.
El siguiente método demuestra cómo crear JWT personalizados:
- El servicio App Identity se utiliza para obtener automáticamente el correo electrónico de la cuenta de servicio.
- Se construye el encabezado del token.
- Las reclamaciones se agregan a la carga útil del token de acuerdo con la documentación de autenticación de Firebase.
La más importante de estas reclamaciones es
uid
, que es el identificador de canal de usuario único que restringe el acceso a un solo usuario. - Por último, el servicio App Identity se utiliza nuevamente para firmar el token.
Python
Java
El servidor ejecuta la función anterior y pasa el token a la plantilla que se va a procesar en el cliente. En esta aplicación de tres en línea de ejemplo, el ID de usuario del jugador y la clave del juego comprenden el uid
para la autorización de Firebase.
Autenticar el cliente de JavaScript
Después de que los tokens se hayan generado en el servidor y pasado al HTML del cliente, el cliente puede usarlos para autorizar los comandos de lectura y escritura.
Solo es necesario autenticar al cliente una vez y, a continuación, se autentican todas las llamadas subsiguientes que utilizan el objeto firebase
. El código de muestra ilustra cómo hacerlo:
Python
Java
Actualizar las reglas de seguridad de la base de datos de Firebase
En la sección Base de datos de Firebase console, selecciona la pestaña Reglas.
A continuación, actualiza las reglas de seguridad de Firebase para restringir el acceso solo a las conexiones autorizadas. Específicamente, restringe las escrituras al servidor y permite solo las lecturas cuando el ID único del usuario, uid
, en la carga útil de autorización coincide con el ID único en la ruta de la base de datos.
{
"rules": {
".read": false,
".write": false,
"channels": {
"$channelId": {
// Require auth token ID to match the path the client is trying to read
".read": "auth.uid == $channelId",
".write": false
}
}
}
}
Hacer una revisión general en la aplicación de muestra
Para ilustrar mejor cómo usar Firebase a fin de compilar aplicaciones en tiempo real, observa la aplicación del juego de tres en línea de muestra. El código fuente completo de la aplicación para Python está disponible en la página de GitHub de Fire Tac Toe. El código fuente completo de la aplicación para Java está disponible en la página de GitHub de Fire Tac Toe.
El juego permite a los usuarios crear un juego, invitar a otro jugador mediante el envío de una URL y jugar de manera conjunta en tiempo real. La aplicación actualiza las vistas de ambos jugadores del tablero, en tiempo real, tan pronto como el otro jugador hace un movimiento.
En el resto de este artículo, se revisan los aspectos más destacados que ilustran las capacidades clave.
Conectarse a una ruta de Firebase
Cuando un usuario visita el juego por primera vez, se producen dos situaciones:
- El servidor del juego inyecta un token en la página HTML que se envía al cliente. El cliente utiliza este token para abrir una conexión a Firebase y detectar las actualizaciones. La única ruta que el usuario detecta es
/channels/[USER_ID + GAME_KEY]
. - El servidor del juego proporciona al usuario una URL que puede compartir con un amigo para invitarlo a unirse al juego.
El siguiente código del lado del servidor crea una ruta de Firebase para la aplicación del juego y lo inyecta en el HTML del cliente:
Python
Java
Ahora, el cliente web utiliza el token para detectar la ruta /channels/[USER_ID + GAME_KEY]
.
Esto sucede en la función openChannel()
. Se agrega un objeto de escucha para seguir los cambios en el valor de la ruta. El método <reference>.on()
de Firebase se utiliza para configurar una devolución de llamada que se ejecuta en los cambios de valor en este caso. Cuando cambia el valor de la ruta de la base de datos, se llama al método onMessage()
para actualizar el estado del juego y la IU del usuario.
Python
...
Java
...
Enviar actualizaciones al servidor
Cuando el usuario realiza un movimiento, se llama al método moveInSquare()
, que verifica que el movimiento sea válido, y envía una solicitud POST
HTTP al servidor con la ubicación del movimiento.
Python
Java
El servidor recibe la solicitud POST
de HTTP y se llama al controlador para la ruta /move
. Este controlador identifica al usuario y extrae la ubicación del cuadrado de la solicitud. Luego, realiza el movimiento; para ello, llama al método en el objeto Game
:
Python
Java
El método que realiza el movimiento completa una ronda final de validación en el movimiento del usuario, comprueba si el usuario ganó el juego y escribe el estado del juego en el almacén de datos. Por último, llama a un método para actualizar el estado del juego en Firebase.
Python
Java
El método de actualización llama entonces al método que definiste anteriormente para realizar la solicitud HTTP en Firebase:
Python
Java
Por último, realiza la solicitud HTTP:
Python
Java
Después de esta llamada a Firebase, los clientes web reciben el estado actualizado del juego de inmediato, sin sondear el servidor.
Quitar objetos de escucha y borrar datos
Cuando un jugador ganó el juego, no hay información adicional para enviar desde el servidor. En este caso, debes quitar los objetos de escucha y borrar los datos del juego desde Firebase porque el almacenamiento no necesariamente es gratuito. Para hacerlo, llama al método off()
en la referencia de Firebase que los clientes han detectado. Por último, el cliente envía un mensaje al servidor en el extremo /delete
, que quita los datos almacenados para el juego que terminó.
Python
...
Java
...
Borra los datos en Firebase; para ello, presiona el controlador del extremo /delete
:
Python
Java
Pasos siguientes
- Prueba otras características de Google Cloud Platform por ti mismo. Revisa nuestros instructivos.