Categorías
Cloud Firebase Google Cloud

Cómo configurar los backups de Firestore desde la consola de gcloud

Antes que nada, toda la documentación oficial está en: https://firebase.google.com/docs/firestore/backups

Instalar la consola para Google Cloud

Para comenzar, se requiere tener instalada la consola de gcloud. En este link https://cloud.google.com/sdk/docs/install?hl=es-419 podrás descargar los instaladores y ver las instrucciones para la instalación. Una vez instalada, se podrán configurar los proyectos.

Categorías
Angular Dev TypeScript

Cómo extender la clase Error en TypeScript para manejar mejor los Errores en una aplicación

El manejo de errores es uno de los grandes faltantes en la mayoría de tutoriales disponibles en la web. Muchas veces, simplemente lanzar instancias de Error no es suficiente para poder lidiar con los diferentes tipos de Error que puede emitir una clase o una función.

Esto es aun peor cuando se consumen APIs externas, que pueden emitir muchos tipos diferentes de errores, que en cada caso habrá que manejar apropiadamente y de manera diferente.

El primer paso para lograrlo es extender la clase Error, para que pueda ser un poco más descriptiva:

export class Failure extends Error {
  public code = '';
  constructor(message: string, code: string | null = null) {
    super(message);
    if (code) {
      this.code = code;
    }
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

Ahora contamos con una clase Failure, que extiende Error y que adicional nos permite tener un code, que en algunos casos es muy útil. Ahora es solo cuestión de extender dicha clase para cada uno nuestros errores:

export class NotFoundFailure extends Failure {}
export class UnknownFailure extends Failure {}

Así, en nuestro código podemos lanzar errores específicos y documentar apropiadamente nuestras funciones, indicando que también devuelven ‘never’, es decir, que podrían emitir un error. El ejemplo a continuación intenta ilustrarlo. Usen su imaginación!:

export class CosaClient {
  // ...

  /**
   * Devuelve una Cosa.
   * ...
   *
   * @throws NotFoundFailure | UnknownFailure
   */
  fetchId(id: string): Promise<Cosa | never> {
    // ...
    
    // Tirar un error!
    if (...) {
    throw new NotFoundFailure('Mensaje', '123');

    // ...

    // Tirar otro error!
    if (...) {
      throw new UnknownFailure('Mensaje', '123');
    }

    // ...
  }
}

Luego, cuando hagamos uso de la clase CosaClient, podemos saber por la documentación que emite determinados errores y hacer el manejo apropiado de ellos:

try {
  // Instanciar la clase.
  const cosaClient = new CosaClient();

  // Recuperar el ID 123.
  const cosa = CosaClient.fetchId('123');

  // ...

// Manejar los errores que puedan ocurrir en el catch.
} catch (e) {

  if (e instanceof NotFoundFailure) {
    // Decirle al usuario que ese ID no existe.

  } else if (e instanceof UnknownFailure) {
    // Decirle al usuario que ocurrió un error inesperado.

  } else if (e instanceof Error) {
    // Manejar cualquier error genérico que venga de otra parte.

  } else {
    // Manejar cualquier otra cosa inesperada.
  }
}

Finalmente, cómo nuestros propios Failures cuentan con campos para un mensaje y un código de error, podremos tener mensajes más claros y hacer un mejor manejo con las variantes de cada error.

¡Espero que esto les de ideas de como lidiar mejor con sus Errores!

Categorías
Cloud Firebase Google Cloud

Como crear un bucket en Google Cloud

Categorías
Cloud Google Cloud Wordpress

Notas sobre WordPress en Google Cloud con Bitnami

Lo primero es que lo más cerquita a Colombia son las zonas us-east1.

En bitnami el usuario root de la base de datos es root y la contraseña es la misma del usuario admin de wordpress, que sale como Admin password (Temporary) en el panel de la instalación en Google Cloud. Cómo bitnami está configurado para solo permitir el acceso a mysql vía ssh, entonces no es un problema de seguridad que el usuario sea root, pero si es sano cambiar la contraseña por lo menos.

Categorías
Angular Dev

RxJS Operators (operadores) para dummies

Cómo RxJS se pone bastante extraño y complejo rápidamente, aquí les comparto una explicación de coquito de varios de los operadores más usados:

https://scotch.io/tutorials/rxjs-operators-for-dummies-forkjoin-zip-combinelatest-withlatestfrom/amp

Por otra parte, les comparto un artículo con 5 usos comunes de estos operadores:

https://medium.com/grensesnittet/5-helpful-rxjs-solutions-d34f7c2f1cd9

Categorías
Cloud Firebase Google Cloud

Como correr el Emulador de Firebase con datos del prod y mover datos entre proyectos

Lo primero que diré es que Google Cloud Console tiene herramientas 2 herramientas importantes:

Firestore > Import/Export: para hacer backups y restablecer los datos de firestore.

Cloud Storage: Para administrar los archivos de los backups.

Categorías
Angular Dev Firebase

Cómo resolver el error @firebase/firestore: Firestore (8.2.2): FIRESTORE (8.2.2) INTERNAL ASSERTION FAILED: Unexpected state en Angular con Firebase

El error @firebase/firestore: Firestore (8.2.2): FIRESTORE (8.2.2) INTERNAL ASSERTION FAILED: Unexpected state no está muy bien documentado y se presenta cuando uno esta depurando una app en Angular con Firebase, utilizando Google Chrome. Está relacionado con la opción enablePersistence y se resuelve abriendo la consola de depuración del navegador y en la pestaña Application, checkear la opción IndexedDB y borrar los datos.

Categorías
Angular Dev Firebase TypeScript

Cómo contar registros fácil y rápido en firebase

Partiendo de que ya se tenga un proyecto en Typescript con Firebase configurado, basta con crear la siguiente función:

Categorías
Angular Dev TypeScript

Sobre fechas y toLocaleDateString()

Es posible convertir un objeto Date en UTC a una fecha en hora local usando toLocaleDateString(). Toda la información de como hacerlo está aquí:

Categorías
Angular Dev Firebase TypeScript

Adaptador para un selector de fechas en Angular

Firebase entrega TimeStamps, no fechas, por lo que toca hacer la conversión respectiva. Pero es posible implementar una directiva que resuelva este problema así: