#impr3siones – #PR3 Subida de ficheros a Cloud Storage
En esta tercera entrega de #impr3siones añadimos subida de archivos mediante el sdk de firebase a Cloud Storage y configuramos una función que se ejecuta cuando se sube un archivo. Además reestructuramos los conectores, para poder tenerlos divididos en base a la función que tienen.
Nueva organización de los conectores
Esta PR introduce mas cambios en la reorganización que código nuevo, así que vamos a explicar los conectores que tenemos y cómo se usan, y cuando lleguemos al de storage explicamos cómo funciona.
A partir de ahora tenemos un el archivo «packages/data-connector/src/firebase/connectors.ts» en el cual se instancian todos los conectores, como se muestra a continuación.
const app = initializeApp(firebaseConfig);
const firebaseDatabase = getDatabase(app);
const firebaseAuth = getAuth(app);
const firebaseStorage = getStorage(app);
if (shouldConnectToEmulator()) {
connectAuthEmulator(firebaseAuth, 'http://localhost:9099');
connectDatabaseEmulator(firebaseDatabase, 'localhost', 9000);
connectStorageEmulator(firebaseStorage, 'localhost', 9199);
}
export const auth = new AuthConnector(firebaseAuth);
export const orders = new OrdersConnector(firebaseDatabase);
export const storage = new StorageConnector(firebaseStorage, auth);
Lo que hemos hecho ha sido sacar la inicialización de los módulos de Firebase de la lógica de los conectores e inyectar en el constructor las dependencias necesarias para cada uno de los conectores. De esta manera los conectores no tienen que tener detalles de inicialización de los módulos o si es necesario conectar al emulador.
Los conectores
El tener los conectores desacoplados de esta manera nos permitiría por ejemplo mover el sistema de autenticación a otro proveedor, o separar los pedidos a una nueva base de datos en AWS o en Azure y que todo siguiera funcionando.
Autenticación
Este conector lo vamos a usar para todo lo que tiene que ver con la autenticación y sesión de usuario. Tiene sus métodos de login y logout, y gestiona los listeners para notificar cuando haya un cambio de sesión.
Base de datos
No tendremos un conector único para la base de datos, puesto que tendremos datos de usuario, pedidos, impresiones etc… y para cada una de estas entidades tendremos un conector distinto. Cuando tengamos casos de usos que abarquen varias entidades crearemos un nuevo conector al que inyectar los conectores de esas entidades.
Pedidos
Este conector nos sirve para ver cómo se crea un conector de una entidad simple como son los pedidos.
Almacenamiento
¡Por fin llegamos a la parte de subir archivos! Este conector nos servirá para subir archivos y depende del de autenticación ya que necesitamos añadir metadatos de qué usuario ha subido un archivo.
Existen dos maneras de subir datos con el sdk de Firebase, con el método uploadBytes que nos devuelve una promesa con el resultado o, nuestro caso, con el método uploadBytesResumable el cual devuelve una UploadTask que nos permite monitorizar el estado de la subida, y además pausar o continuar la propia subida.
Para monitorizar el progreso de una subida tenemos un nuevo listener:
export type UploadStatusUpdatedListener = (
status: UploadStatus,
progress: number,
downloadUrl?: string
) => void;
El cual será llamado varias veces durante la subida del archivo actualizando el progreso, y cuando se haya subido correctamente nos pasará la url de descarga del archivo.
¿Qué hacemos cuando se sube un archivo?
Firebase functions tiene un disparadores de Cloud Storage, que se pueden ejecutar cuando se crea o modifica un archivo. De momento hemos configurado esta función que se dispara cuando se sube el archivo y hace un log del nombre y los metadatos.
export default region('europe-west1')
.storage.object()
.onFinalize(async (object): Promise<void> => {
console.log(
`Uploaded file to ${object.name} and metadata ${JSON.stringify(
object.metadata
)}`
);
});
¿Cómo se protegen los archivos de Cloud Storage?
Firebase permite definir un fichero de reglas para el acceso y escritura de los archivos, al igual que con Realtime Database. De momento y puesto que solamente estamos haciendo pruebas con el emulador, tenemos el mismo archivo que creamos al hacer la estructura del proyecto, el cual puedes ver aqui, y que nos permite subir archivos si estamos autenticados y da permisos de lectura a todo el mundo.
Añadir nuevos proveedores
Observarás que de momento todos los conectores están bajo la carpeta firebase, y que las clases están muy acopladas al SDK. Si en algún momento queremos añadir un nuevo proveedor para algún conector tendremos que seguir estos pasos.
- Crear las interfaces de los conectores afectados.
- Renombrar los conectores actuales.
- Crear los nuevos conectores.
- Añadir la lógica necesaria para instanciar y exponer los conectores de los proveedores adecuados, manteniendo la interfaz actual.
Todos estos pasos los daremos en un futuro si fuera necesario, de momento con tenerlos en cuenta creo que es suficiente.
Creo que ya podemos pensar los casos de uso que queremos implementar para la fase 1 del MVP y empezar a plantear el frontend. ¡Nos vemos en la próxima entrada!