Introduction to Firebase

Firebase is a platform developed by Google that offers a suite of services to help developers build, test, and deploy apps quickly. It provides a wide range of features, including real-time database, authentication, cloud functions, hosting, and more. Firebase’s ease of use and seamless integration with both web and mobile platforms make it an ideal choice for developers aiming to streamline their development workflow.

Setting Up Firebase

Before we dive into the code examples, let’s set up a Firebase project. Follow these steps to get started:

  1. Create a Firebase Project:
  • Visit the Firebase Console and click on “Add Project.”
  • Enter your project name and select your region.
  1. Configure Firebase for Your App:
  • After creating the project, click on “Add app” to add your web or mobile app.
  • Follow the setup instructions to add Firebase to your project.
  1. Obtain Firebase Configuration:

Once the app is added, Firebase will provide you with a configuration object containing API keys and other details. Keep this information handy as we’ll use it in our code examples. Now that we have our Firebase project set up, let’s explore some of its core features through practical code examples.

Firebase Authentication

Firebase provides a simple and secure authentication system, making it easy to implement user authentication in your apps. Let’s look at an example of setting up Firebase Authentication with email and password.

In this example, we initialize the Firebase Authentication service, and we demonstrate how to sign up, sign in, and sign out a user.

import { initializeApp } from "firebase/app";
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth";

// Initialize Firebase Authentication and get a reference to the service
const auth = getAuth(app);

//Create a new User using Email And Password
createUserWithEmailAndPassword(auth, email, password)
  .then((userCredential) => {
    // Signed up
    const user = userCredential.user;
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
    // ..
  });

//Sign in an existing User
signInWithEmailAndPassword(auth, email, password)
  .then((userCredential) => {
    // Signed in
    const user = userCredential.user;
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
  });

These examples provided a glimpse into the most fundamental Authentication scenarios. Firebase Authentication further facilitates integration with various platforms, including:

  • Google Sign-in
  • Facebook Login
  • Twitter Login
  • GitHub Login
  • Anonymous sign-in

Additionally, it extends support for Multi-factor authentication and custom authentication systems.

Firebase Database Offerings

Firebase provides two document databases accessible to clients in the cloud.

Firestore stands out as the preferred enterprise-level JSON-compatible document database, earning the trust of over 250,000 developers. It is well-suited for applications featuring intricate data models that demand query capabilities, scalability, and high availability. Additionally, Cloud Firestore offers efficient client synchronization with low latency and supports offline data access.

The Realtime Database, on the other hand, represents the traditional Firebase JSON database. It is suitable for applications with uncomplicated data models that require straightforward lookups and low-latency synchronization but come with limited scalability.

It is possible to employ both databases in a single Firebase app or project. Both NoSQL databases have the capability to store identical data types, and their client libraries operate in a comparable fashion. The decision which one to use is dependent on what the application requires in that specific case.

More information can be found here:

https://firebase.google.com/docs/database/rtdb-vs-firestore

import { initializeApp } from "firebase/app";
import { getDatabase, ref, child, get,set } from "firebase/database";

const firebaseConfig = {
  // ...
  // The value of `databaseURL` depends on the location of the database
  databaseURL: "https://DATABASE_NAME.firebaseio.com",
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);

// Initialize Realtime Database and get a reference to the service
const database = getDatabase(app);

// Basic write operation
set(ref(database, 'users/' + userId), {
    username: name,
    email: email,
    profile_picture : imageUrl
  });

// Basic read operation
get(child(dbRef, `users/${userId}`)).then((snapshot) => {
    if (snapshot.exists()) {
      console.log(snapshot.val());
    } else {
      console.log("No data available");
    }
  }).catch((error) => {
    console.error(error);
  });
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
  FIREBASE_CONFIGURATION,
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);

// Initialize Cloud Firestore and get a reference to the service
const db = getFirestore(app);

// Basic write operation
const docRef = await addDoc(collection(db, "users"), {
  first: "Ada",
  last: "Lovelace",
  born: 1815,
});

// Basic read operation
const querySnapshot = await getDocs(collection(db, "users"));
querySnapshot.forEach((doc) => {
  console.log(`${doc.id} => ${doc.data()}`);
});

As evident from these fundamental examples, the Firestore option features a more straightforward syntax, potentially facilitating a smoother onboarding experience for users.

Cloud Functions with Firebase

Google Firebase Cloud Functions is a serverless computing service that enables developers to deploy and execute event-driven functions in response to various cloud-based events. At its core, this service allows developers to write server-side code without the need to manage servers, providing a streamlined and efficient approach to application development. These functions can be deployed and executed in a scalable manner, automatically adjusting to the workload without manual intervention. This flexibility is particularly advantageous for handling varying workloads and ensuring optimal resource utilization.

// Take the text parameter passed to this HTTP endpoint and insert it into
// Firestore under the path /storage/:documentId/original
exports.storetofirestore = onRequest(async (req, res) => {
    // Grab the text parameter.
    const original = req.query.text;
    // Push the text into Firestore using the Firebase Admin SDK.
    const storageResult = await getFirestore()
        .collection("storage")
        .add({original: original});
    // Send back a response that we've successfully stored the text
    res.json({result: `Stored with ID: ${storageResult.id}.`});
});

Cloud Functions are designed to respond to various triggers, such as changes in data within Firebase Realtime Database, updates to Cloud Storage objects, or HTTP requests. This event-driven architecture allows developers to create dynamic and responsive applications by executing specific functions in response to specific events, enhancing the overall agility and functionality of the application.

import {
    onDocumentCreated,
    Change,
    FirestoreEvent
} from "firebase-functions/v2/firestore";

exports.createuser = onDocumentCreated("message/{messageId}", (event) => {
    //Get the firestore database object which was created
    const snapshot = event.data;

    if (!snapshot) {
        console.log("No data associated with the event");
        return;
    }
    //data from the document created eg. { text: "Hello World" }
    const data = snapshot.data();

    console.log("There was an object created with the data:", data)
});

Cloud Functions are designed to respond to various triggers, such as changes in data within Firebase Realtime Database, updates to Cloud Storage objects, or HTTP requests. This event-driven architecture allows developers to create dynamic and responsive applications by executing specific functions in response to specific events, enhancing the overall agility and functionality of the application.

import {
    onDocumentCreated,
    Change,
    FirestoreEvent
} from "firebase-functions/v2/firestore";

exports.createuser = onDocumentCreated("message/{messageId}", (event) => {
    //Get the firestore database object which was created
    const snapshot = event.data;

    if (!snapshot) {
        console.log("No data associated with the event");
        return;
    }
    //data from the document created eg. { text: "Hello World" }
    const data = snapshot.data();

    console.log("There was an object created with the data:", data)
});

Functions can be invoked directly, as illustrated in a previous example utilizing an HTTP request. Alternatively, they can be triggered through the app using Firebase integration, executed on a scheduled basis, or processed via a task queue. The task queue facilitates the asynchronous handling of tasks that are time-consuming, resource-intensive, or constrained by bandwidth, providing a versatile approach to manage various types of functions within the application.

//Task can be run manually here: https://console.cloud.google.com/cloudscheduler
exports.eraseExpired = onSchedule("every day 00:00", async (event) => {
    // Fetch all user details.
    const expiredAccounts = await getExpiredAccounts();

    // Use a pool so that we delete maximum `MAX_CONCURRENT` users in parallel.
    const promisePool = new PromisePool(
        () => deleteExpiredAccounts(expiredAccounts),
        MAX_CONCURRENT,
    );
    await promisePool.start();

    logger.log("Expired users deleted");
});

The serverless nature of Firebase Cloud Functions eliminates the need for developers to manage infrastructure, enabling them to focus solely on writing code to meet the specific requirements of their application. This simplicity in deployment and management accelerates the development process and allows developers to iterate quickly.

Cloud Functions for Firebase automatically adjusts the number of active instances in response to incoming requests, scaling down to zero during periods of low traffic. However, if optimizing for reduced latency and minimizing cold starts is essential for your application, you have the option to customize this behavior. Specify a minimum number of container instances to be maintained in a warmed-up state, ready to promptly handle incoming requests, deviating from the default scaling approach.

const { onCall } = require("firebase-functions/v2/https");

exports.getUser = onCall(
    {
      // Keep at least 1 instance warm
      minInstances: 1,
    },
    (event) => {
      // Retrieves user data
    }
);

Firebase Hosting

Firebase Hosting, part of Google’s Firebase platform, is a robust and user-friendly web hosting service designed to simplify the deployment and hosting of web applications. It provides developers with a seamless solution for serving both static and dynamic content on a global scale.

A standout feature of Firebase Hosting is its seamless integration with other Firebase services, establishing a unified ecosystem for comprehensive app development. It supports the easy deployment of web applications built with popular frameworks like Angular, React, or Vue.js, ensuring compatibility across diverse development stacks.

Noteworthy is Firebase Hosting’s reliance on a content delivery network (CDN) that strategically distributes web content across multiple servers worldwide. This approach not only guarantees low-latency access for users but also significantly enhances overall performance and reliability. The platform prioritizes security with SSL support, safeguarding connections for modern web applications.

Firebase Hosting excels in deployment capabilities, allowing developers to effortlessly deploy applications using a straightforward command-line interface or directly through the Firebase console. Furthermore, it facilitates continuous deployment by seamlessly integrating with version control systems like Git, automating the deployment of updates and changes to the codebase. These features collectively streamline the development workflow, making Firebase Hosting an invaluable tool for hosting and scaling web projects efficiently.

Firebase Emulation

The Firebase Local Emulator Suite comprises sophisticated tools tailored for developers who aim to construct and test applications locally. This comprehensive suite includes support for Cloud Firestore, Realtime Database, Cloud Storage for Firebase, Authentication, Firebase Hosting, Cloud Functions (beta), Pub/Sub (beta), and Firebase Extensions (beta). Equipped with a user-friendly interface, the Local Emulator Suite expedites the setup process and aids in swift prototyping.

Employing the Local Emulator Suite for local development proves advantageous in scenarios such as evaluation, prototyping, development, and integration workflows. This versatile solution seamlessly aligns with your development needs, offering a robust framework for testing and refining your applications in a localized environment before deployment.

//run emulator suite
firebase emulators:start
//THE UI is now running and can be found at http://localhost:4000

// connect to the firestore emulator
import { getFirestore, connectFirestoreEmulator } from "firebase/firestore";

// connect to the firestore emulator
const db = getFirestore();
connectFirestoreEmulator(db, '127.0.0.1', 8080);

Firebase emulators

Conclusion

Firebase is a powerful and versatile platform that significantly accelerates app development without compromising functionality. In this blog post, we explored key features such as database solutions, authentication, Cloud Functions, Emulation and Hosting.

By leveraging Firebase, developers can focus more on building innovative features and less on managing infrastructure. Whether you’re a solo developer working on a side project or part of a larger team building a production-grade application, Firebase offers a scalable and efficient solution for your app development needs.

Incorporate Firebase into your development workflow and experience the speed, flexibility, and reliability it brings to your projects. Happy coding!