Manejar sesiones con Firestore

En muchas apps, se necesita controlar las sesiones para la autenticación y las preferencias del usuario. En Sinatra, se incluye una implementación basada en la memoria para realizar esta función. Sin embargo, esta implementación no es adecuada para una app que se puede entregar desde varias instancias, ya que la sesión que se registra en una instancia puede diferir de otras instancias. En este instructivo, se muestra cómo controlar sesiones en App Engine.

Objetivos

  • Escribe la aplicación.
  • Ejecuta la aplicación de manera local.
  • Implementa la aplicación en App Engine.

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso proyectado, usa la calculadora de precios. Es posible que los usuarios nuevos de Google Cloud califiquen para obtener una prueba gratuita.

Cuando finalices este instructivo, podrás borrar los recursos creados para evitar que se te siga facturando. Para obtener más información, consulta cómo hacer una limpieza.

Antes de comenzar

  1. Accede a tu Cuenta de Google.

    Si todavía no tienes una cuenta, regístrate para obtener una nueva.

  2. En la página Selector de proyectos de Cloud Console, selecciona o crea un proyecto de Cloud.

    Ir a la página Selector de proyectos

  3. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información sobre cómo confirmar que tienes habilitada la facturación para tu proyecto.

  4. Habilita la API de Firestore.

    Habilita la API

  5. Prepara el entorno de desarrollo.

Prepara el proyecto

  1. En la ventana de tu terminal, comienza en un directorio de tu elección y crea un directorio nuevo llamado sessions. Todo el código para este instructivo está dentro del directorio sessions.

  2. Cambia al directorio sessions con el siguiente comando:

    cd sessions
    
  3. Inicializa el Gemfile:

    bundle init
    
  4. Agrega lo siguiente al Gemfile resultante:

    gem "google-cloud-firestore", "~> 1.2"
    gem "sinatra", "~> 2.0"

    En el Gemfile, se enumeran las bibliotecas de Ruby no estándar que debe cargar App Engine para ejecutar la app:

    • google-cloud-firestore es el cliente de Ruby para la API de Firestore.

    • Sinatra es el framework web de Ruby que se usa para la app.

  5. Instala las dependencias

    bundle install
    

Escribe la aplicación web

Esta app muestra saludos en diferentes idiomas para cada usuario. A los usuarios recurrentes se los saluda siempre en el mismo idioma.

  • Con un editor de texto, crea un archivo llamado app.rb en el directorio sessions con el siguiente contenido:

    require "sinatra"
    
    require_relative "firestore_session"
    
    use Rack::Session::FirestoreSession
    
    set :greetings, ["Hello World", "Hallo Welt", "Ciao Mondo", "Salut le Monde", "Hola Mundo"]
    
    get "/" do
      session[:greeting] ||= settings.greetings.sample
      session[:views] ||= 0
      session[:views] += 1
      "<h1>#{session[:views]} views for \"#{session[:greeting]}\"</h1>"
    end

Crea el almacén de sesiones

Antes de que se puedan guardar las preferencias de un usuario en tu aplicación, necesitas una forma de almacenar información sobre el usuario actual en una sesión. En el siguiente diagrama, se muestra cómo Firestore controla las sesiones de la aplicación de App Engine.

Diagrama de arquitectura: usuario, App Engine, Firestore

Sinatra tiene compatibilidad integrada para guardar datos de sesión en una cookie. Para guardar en Firestore, debes definir tu propio objeto Rack::Session.

  • En el directorio sessions, crea un archivo llamado firestore_session.rb con el siguiente contenido:

    require "google/cloud/firestore"
    require "rack/session/abstract/id"
    
    module Rack
      module Session
        class FirestoreSession < Abstract::Persisted
          def initialize app, options = {}
            super
    
            @firestore = Google::Cloud::Firestore.new
            @col = @firestore.col "sessions"
          end
    
          def find_session _req, session_id
            return [generate_sid, {}] if session_id.nil?
    
            doc = @col.doc session_id
            fields = doc.get.fields || {}
            [session_id, stringify_keys(fields)]
          end
    
          def write_session _req, session_id, new_session, _opts
            doc = @col.doc session_id
            doc.set new_session, merge: true
            session_id
          end
    
          def delete_session _req, session_id, _opts
            doc = @col.doc session_id
            doc.delete
            generate_sid
          end
    
          def stringify_keys hash
            new_hash = {}
            hash.each do |k, v|
              new_hash[k.to_s] =
                if v.is_a? Hash
                  stringify_keys v
                else
                  v
                end
            end
            new_hash
          end
        end
      end
    end

Borra sesiones

Tal como está escrita, esta app no borra las sesiones anteriores o vencidas. Puedes borrar los datos de la sesión en Google Cloud Console o implementar una estrategia de eliminación automática.

Ejecución local

  1. Inicia el servidor HTTP:

    bundle exec ruby app.rb
    
  2. Visualiza la app en el navegador web.

    Verás uno de los cinco saludos: "Hello World", "Hallo Welt", "Hola mundo", "Salut le Monde" o "Ciao Móndo". El idioma cambia si abres la página en otro navegador o en modo Incógnito. Puedes ver y editar los datos de la sesión en Google Cloud Console.

  3. Para detener el servidor HTTP, presiona Control+C en la ventana de la terminal.

Implementa y ejecuta en App Engine

Puedes usar el entorno estándar de App Engine para compilar y también implementar una aplicación que se ejecute de manera confiable con cargas pesadas y grandes cantidades de datos.

En este instructivo, se usa el entorno estándar de App Engine para implementar el servidor.

  1. En la ventana de la terminal, crea un archivo app.yaml y pega lo siguiente en el archivo:

    runtime: ruby25
    entrypoint: bundle exec ruby app.rb
  2. Implementa la aplicación en App Engine con el comando siguiente:

    gcloud app deploy
    
  3. Visualiza la aplicación en vivo en la URL siguiente, en la que PROJECT_ID es tu ID del proyecto de Google Cloud:

    https://PROJECT_ID.appspot.com

El saludo ahora se entrega en un servidor web que se ejecuta en una instancia de App Engine.

Depura la app

Si no puedes conectarte a la aplicación de App Engine, verifica lo siguiente:

  1. Comprueba que los comandos de implementación de gcloud se completaron correctamente y no generaron ningún error. Si hubo errores (por ejemplo, message=Build failed), corrígelos y, luego, intenta implementar la aplicación de App Engine nuevamente.
  2. En Cloud Console, ve a la página Visor de registros.

    Ir a la página Visor de registros

    1. En la lista desplegable Recursos seleccionados recientemente, haz clic en Aplicación de App Engine y, luego, haz clic en Todos module_id. Verás una lista de las solicitudes de cuando visitaste tu aplicación. Si no ves una lista de solicitudes, confirma que seleccionaste Todos module_id en la lista desplegable. Si ves mensajes de error impresos en Cloud Console, comprueba que el código de tu aplicación coincida con el código de la sección sobre escritura de la aplicación web.

    2. Asegúrate de que la API de Firestore esté habilitada.

Limpieza

Borra el proyecto

  1. En Cloud Console, ve a la página Administrar recursos.

    Ir a la página Administrar recursos

  2. En la lista de proyectos, selecciona el proyecto que deseas borrar y haz clic en Borrar .
  3. En el cuadro de diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Borra la instancia de App Engine

  1. En Cloud Console, ve a la página Versiones de App Engine.

    Ir a la página Versiones

  2. Selecciona la casilla de verificación de la versión no predeterminada de la app que deseas borrar.
  3. Haz clic en Borrar para borrar la versión de la app.

Próximos pasos