portada guia firebase

Firebase: Guía práctica – Parte #1

Última actualización:

En ocasiones, cuando creamos páginas web, necesitamos almacenar ciertos datos para poder utilizarnos en nuestra web. Para almacenar esos datos existen las bases de datos (en inglés, databases).

Los datos almacenados en la database que vamos a explicar en esta serie no se almacenan en nuestro ordenador, sino en un servidor web. Además, no necesitaremos utilizar un lenguaje del lado del servidor (un lenguaje de backend)porque podemos trabajar con Firebase. 🔥

Firebase nos permite utilizar una database y comunicarnos con ella directamente desde nuestro código JavaScript (en adelante, JS). 

Tipos de databases

tipos databases

Existen dos tipos principales de databases: las SQL y las noSQL. Las SQL databases son muy populares entre lenguajes como PHP, mientras que las noSQL funcionan genial con lenguajes como JS. Por eso en esta serie de posts vamos a trabajar con una noSQL database: Firebase / Firestore. 💪

Funcionamiento de las NoSQL databases

Una noSQL database almacena nuestros datos en una especie de contenedor al que llama database instanceDentro de ese contenedor, la database clasifica nuestros datos según el tipo que sean, y los separa en diferentes "secciones" llamadas collections

Así, podemos tener una collection que almacene títulos de películas, otra que almacene ingredientes de una pizza, otra que almacene listas de tareas, etc. Dentro de cada collection se almacenan los documentsque representan un único valor. Por ejemplo, dentro de la collection de los ingredientes de una pizza, tendríamos un document que guardaría el valor "mozzarella", otro con "salmón", etc. Cada document tiene un ID único que lo identifica.

Un document tiene un aspecto muy parecido a un objeto de JS, ya que se compone de key-value pairs.  

noSQL estructura

Primeros pasos con Firebase y Firestore

La database que vamos a explicar en esta serie se llama Firestore, a la que tenemos acceso a través de un servicio llamado Firebase, cuyo dueño es Google, por cierto 😎. Firebase es técnicamente un servicio de backend (en inglés, backend as a service). Esto significa que nos proporciona una solución completa de backend, evitándonos la creación de un servidor y el uso de lenguajes de backend. 

Firebase viene cargado de fábrica con características como authentication,  hosting, cloud storage, y, la más importante para nosotros, una database en tiempo real, o su versión más moderna, una database en la nube (cloud Firestore). 😯 🌥

Es gratis para apps pequeñas y es necesario registrarse. Si ya tienes una cuenta de google, podrás registrarte con ella. Y ahora sí, comienza la aventura. 🤠

1. Una vez registrado, en el menú superior encontrarás el botón "go to console". Ahí vamos. Eso nos lleva a nuestra Firebase console, única para cada usuario de Firebase.

caracteristicas firebase

Dentro de la Firebase console veremos todos nuestros proyectos, que en mi caso es ninguno 😌. Así que voy a seguir los pasos para crear uno nuevo. Una vez creado, Firebase nos lleva al panel de control de mi proyecto (en inglés, dashboard). 

2. En el menú lateral izquierdo encontramos todas las características que nos ofrece Firebase. Hacemos click en Databaseya que lo que queremos es crear una database. Aquí un vídeo-resumen sobre lo que Cloud Firestore puede hacer por nosotros:

Le damos a "crear base de datos" y se nos abre una ventana con dos opciones sobre seguridad.

firebase security rules

Por defecto viene marcada la opción de "modo de producción", porque es la más segura. Pero no es la que queremos de momento, porque eso no nos permitiría interactuar con nuestros datos como necesitamos. Así que seleccionamos la opción "modo de prueba". 🙋‍♀️ Pero ten en cuenta que al finalizar un proyecto siempre deberías volver al "modo de producción" o definir tus propias reglas de seguridad. 

Esto nos debería llevar al panel de control de Database:

captura database panel de control

¡Ya estamos dentro! 🙆‍♀️ Vamos a añadir nuestra primera collection (Iniciar colección). La llamamos recipes. 🥡

3. Ahora nos pide que añadamos nuestro primer documentasí que lo creamos. Lo lógico aquí es crear una receta, darle un título y un valor. Podemos añadir tantos campos como queramos dentro del mismo document. Por ejemplo, el título de la receta, el autor, la fecha de publicación, etc. 

Dejamos el "ID del documento" en blanco, porque así Firestore le asignará un ID único de forma automática

detalles document firestore

Vamos a añadir otro document dentro de la colección (o sea, otra receta). Con estos dos documents creados, ya podemos empezar a interactuar con nuestra database desde nuestro código. ¡Vamos a ello! 👾

Cómo conectar Firestore con nuestro código

Para esta parte vamos a trabajar con un archivo HTML y un archivo JS. Los llamaremos index.html sandbox.js respectivamente. También vamos a trabajar con Bootstrap 4 para tener un diseño decente en un santiamén y poder centrarnos en aprender sobre Firebase / Firestore. 

1. Creamos un boilerplate en nuestro index.html.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Firebase & Firestore</title>
</head>
<body>
    <script src="sandbox.js"></script>
</body>
</html>

2. Debemos copiar un snippet de código que nos proporciona Firestore para poder conectarnos a nuestra database. Para ello vamos a Project Overview y hacemos click en el icono </>

Le damos un nombre a nuestro proyecto (yo he usado el mismo que le he dado al principio al proyecto) y así accedemos al snippet. Verás que hay dos scriptsEl primero es la propia librería de Firebase. El segundo contiene un objeto llamado config, que contiene, entre otras cosas, una apiKey. Esa apiKey se encarga de indicarle a nuestro frontend a qué backend conectarse. Es un identificador único, vaya. 

3. Copiamos todo el snippet y lo pegamos en el <body> de nuestro index.html, tal y como nos indica el mensaje de arriba del snippet. Asegúrate de pegarlo justo antes del script de sandbox.js, porque en ese archivo vamos a hacer configuraciones que dependerán del snippet de Firebase. 🧐


    <!-- The core Firebase JS SDK is always required and must be listed first -->
    <script src="https://www.gstatic.com/firebasejs/7.3.0/firebase-app.js"></script>
    <!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
    <script>
        // Your web app's Firebase configuration
        var firebaseConfig = {
            apiKey: "AIzaSyBgSTvrraHbVrp1suvuOaEDKvIW5Fc91Q8",
            authDomain: "test-project-firebase-b363d.firebaseapp.com",
            databaseURL: "https://test-project-firebase-b363d.firebaseio.com",
            projectId: "test-project-firebase-b363d",
            storageBucket: "test-project-firebase-b363d.appspot.com",
            messagingSenderId: "464767150557",
            appId: "1:464767150557:web:53e39d195ee070bc342e34"
        };
        // Initialize Firebase
        firebase.initializeApp(firebaseConfig);
    </script>
    <script src="sandbox.js"></script>

Esto no es suficiente, porque necesitamos añadir Cloud Firestore. Subrayado en amarillo verás que Firebase nos avisa de esto, diciendo que podemos añadir todos los servicios de Firebase que necesitemos. En esta sección de su documentación puedes leer cómo añadir Cloud Firestore, para que lo tengas de referencia. 🤓

En cualquier caso, lo único que tenemos que hacer es añadir este script:

<script src="https://www.gstatic.com/firebasejs/7.3.0/firebase-firestore.js"></script>

debajo del comentario subrayando en amarillo.

4. Iniciamos nuestra conexión con la database. Para eso, creamos una variable llamada db y le aplicamos el método firestore al objeto firebase. A todo esto tenemos acceso a través de los scripts de arriba.

        const db = firebase.firestore();

¡Listo! 🤗

Esqueleto HTML + CSS

Vamos a escribir un contenido muy básico en el index.html para poder trabajar con Firebase y ver el resultado en el navegador. Para que se vea decente en el navegador, utilizamos Bootstrap

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
    <div class="container my-5">
        <h3>Recipes</h3>
        <ul>
            <li>Funghi risotto</li>
            <li>Spinach lasagna</li>
        </ul>
        <form>
            <label for="recipe">Add a new recipe:</label>
            <div class="input-group col-lg-6">
                <input type="text" class="form-control" id="recipe" required>
                <div class="input-group-append">
                    <input type="submit" value="add" class="btn btn-outline-primary">
                </div>
            </div>
        </form>
    </div>

Y con esto ya deberíamos tener una interface como esta:

UI app firebase

Cómo obtener y mostrar datos de una collection

Como ya hemos avisado, vamos a usar la constante db para interactuar con nuestra database. Esa constante es como un ancla que hace referencia al conjunto de nuestra database Nuestro objetivo es obtener las recetas y mostrarlas dentro de la lista de recetas, donde ahora están Funghi risotto Spinach lasagna. Todo esto vamos a hacerlo en el sandbox.js. ¡Vamos allá! 👩‍💻

1. Obtenemos una referencia a la recipes collection. Para eso, debemos especificar a qué collection nos queremos referir.

db.collection('recipes');

2. Obtenemos los datos de esa collection usando el método get()Ten en cuenta que este código es asíncrono, porque es una tarea que tarda cierto tiempo en completarse. Eso significa que el código nos devuelve una promesa, a la cual podemos vincularle los métodos then() catch(). Por tanto, lo que configuremos en el then() será lo que se dispare cuando la promesa se resuelva, es decir, cuando recibamos los datos que hemos pedido.

El método catch() lo utilizamos sencillamente para imprimir por consola cualquier error que ocurra en caso de que la promesa sea rechazada.

Al then() le pasamos como parámetro de la callback function un snapshot. 🤳 Un snapshot es una especie de imagen que captura el aspecto que tiene la collection en el preciso momento en el que solicitamos los datos a la database. Probemos a hacer un console.log del snapshot para ver qué obtenemos.

db.collection('recipes').get()
    .then(snapshot => {
        // to do when data is recieved
        console.log(snapshot);
    })
    .catch(err => console.log(err));

Verás que eso nos da un objeto con las propiedades de la recipes collection. 

|   Elements    Console    Sources    Performance    Network    ...

lp {_firestore: Hd, _originalQuery: al, _snapshot: Lh, _cachedChanges: null, _cachedChangesIncludeMetadataChanges: null, …}
    docs: Array(2)
        0: sp {_firestore: Hd, _key: Wi, _document: qs, _fromCache: false, _hasPendingWrites: false}
        1: sp {_firestore: Hd, _key: Wi, _document: qs, _fromCache: false, _hasPendingWrites: false}
        length: 2
        __proto__: Array(0)
    empty: (...)
    metadata: np {hasPendingWrites: false, fromCache: false}
    query: (...)
    size: (...)
    _cachedChanges: null
    _cachedChangesIncludeMetadataChanges: null
    _firestore: Hd {_firebaseApp: T, _queue: Zi, INTERNAL: {…}, _databaseId: Mi, _persistenceKey: "[DEFAULT]", …}
    _originalQuery: al {path: Vi, collectionGroup: null, explicitOrderBy: Array(0), filters: Array(0), limit: null, …}
    _snapshot: Lh {query: al, docs: Rh, oldDocs: Rh, docChanges: Array(2), mutatedKeys: To, …}
    __proto__: Object

Lo que nos interesa es la propiedad docsporque ahí es donde están todos los documents de nuestra collection. Podemos ver dos objetos dentro de docs porque son dos los documents que hemos creado en nuestra database. 

Pero si intentamos buscar en esos objetos los datos que hemos registrado (title, author, created_at), no los encontraremos 😦. Para acceder a ellos debemos usar un método llamado data()que es parte del prototype de cualquiera de los dos documents.

Así accederíamos a los datos del primer document:

        console.log(snapshot.docs[0].data());

Con esto ya deberías ver en la consola los detalles de la primera receta. Así obtendríamos los datos de un solo document, pero lo que queremos es acceder a todos. Para eso simplemente tenemos que barrerlos con un forEach loop. 

db.collection('recipes').get()
    .then(snapshot => {
        // console.log(snapshot.docs[0].data());
        snapshot.forEach(doc => {
            console.log(doc.data());
        });
    })
    .catch(err => console.log(err));

Y así ya podemos ver todos los detalles de cualquier de nuestros documents. 

3. Creamos una HTML template para mostrar nuestras recetas en el navegador (a través del DOM). Para eso, obtenemos una referencia al <ul>, porque es así donde queremos mostrar nuestras recetas. Lo siguiente que haremos será crear una función responsable de crear esa HTML template. 

De momento, solo necesitamos la propiedad title de cada receta. 

La estructura de la HTML template será un sencillo <li>, en línea con lo que ya tenemos en el index.html. Pero como en algún momento mostraremos también otras propiedades, añadimos un <div> dentro del <li> y mostramos ahí el title. Guardamos esa estructura en una variable llamada html y hacemos un console.log de ésta.

Debemos invocar a la función cuando solicitemos los datos de las recetas a la database. 

const list = document.querySelector('ul');
const addRecipe = recipe => {
    let html = `
        <li>
            <div>${recipe.title}</div>
        </li>
    `;
    console.log(html);
};
db.collection('recipes').get()
    .then(snapshot => {
        // console.log(snapshot.docs[0].data());
        snapshot.forEach(doc => {
            // console.log(doc.data());
            addRecipe(doc.data());
        });
    })
    .catch(err => console.log(err));

Así podrás ver en la consola las recetas de la database, en un esqueleto HTML. Genial, ahora vamos a utilizar la propiedad innerHTML para mostrarlas en nuestra web. 

    // console.log(html);
    list.innerHTML += html;

¡Y listo! Ahora ya podemos ver en nuestra web todas las recetas. 👍 👀 🥗

todas las recetas captura

Ya no necesitamos ninguna receta estática (en inglés, hardcoded), así que las borramos del index.html. 

4. Nuestro siguiente paso es mostrar el momento en el que fue creada cada receta. Es decir, mostrar la propiedad created_at. Si nos fijamos en lo que nos devuelve la consola si descomentamos el console.log de doc.data(), verás que nos da un dato con un formato poco útil.

created_at: uo {seconds: 1573426800, nanoseconds: 0}

Pero si desplegamos el prototype de ese objeto, tenemos el método toDate() disponible. Ese es el método que vamos a usar para convertir una fecha a un formato legible y mostrarlo debajo del nombre de la receta, en otro <div> dentro del mismo <li>.

Guardamos el resultado del método toDate() en una variable para que el código quede más limpio y legible. 

    let formattedTime = recipe.created_at.toDate();
    let html = `
        <li>
            <div>${recipe.title}</div>
            <div>${formattedTime}</div>
        </li>
    `;

Y con esto ya deberíamos ver los títulos de las recetas y la fecha de creación debajo de cada una. ¡Chachi!

💁‍♀️   🥣   👏

THE END!

¡Y hasta aquí la primera parte de esta guía de Firebase! Espero que hayas aprendido algo nuevo 😊.  Si te queda alguna duda, ¡nos vemos en los comentarios! Si quieres seguir aprendiendo, aquí tienes la parte #2.

Otros artículos que pueden interesarte

Días del 353 al 386
Objetivos versus realidad Y nuevamente, llegó otro día clave. Llegó…y pasó. El pasado 4 de marzo este Reto Computer Geek[...]
Angular: Entendiendo la Directiva ngModel
Angular es un framework que nos permite, entre otras cosas, añadir contenido dinámico a nuestros archivos HTML. Una de las formas[...]
Días del 2 al 4
"Si buscas resultados distintos no hagas siempre lo mismo" - Albert EinsteinEstos días estoy aprendiendo a hacer loops en JavaScript[...]

¡AH! Si crees que este post puede serle útil a alguien, ¡compártelo!

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Como toda web legal que se precie, utilizamos cookies para asegurar que damos la mejor experiencia al usuario en nuestro sitio web. Si continúas utilizando este sitio asumiremos que estás de acuerdo. más información

Los ajustes de cookies de esta web están configurados para "permitir cookies" y así ofrecerte la mejor experiencia de navegación posible. Si sigues utilizando esta web sin cambiar tus ajustes de cookies o haces clic en "Aceptar" estarás dando tu consentimiento a esto.

Cerrar