DEV Community

Cover image for Introduction to serverless architecture with Firebase and Cloud Functions.

Introduction to serverless architecture with Firebase and Cloud Functions.

Hey there, let's talk about serverless architecture – the game-changer for how we build and deploy applications, offering a cost-effective, scalable, and efficient solution for various use cases. In this article, we're gonna break down the nitty-gritty of serverless architecture, all the cool perks it brings, and how it's given the whole development scene a crazy makeover. So, let's dive into the world of serverless!

What is Serverless Architecture?

Picture this: developers get to create and run apps without even thinking about setting up servers. The real MVP here? The cloud provider takes care of all the behind-the-scenes server stuff, leaving developers free to go wild with their code.This is how serverless architecture allows rapid development, automatic scaling, and reduced operational overhead.

Some key Components of Serverless Architecture

  1. Function as a Service (FaaS): FaaS is at the heart of serverless architecture. Developers write functions that are triggered by events, such as HTTP requests, database changes, or timers. These functions are executed in a stateless manner, allowing them to scale automatically based on demand.

  2. Backend as a Service (BaaS): BaaS complements FaaS by providing pre-built services, such as databases, authentication, file storage, and messaging queues. BaaS eliminates the need to build these components from scratch, enabling faster development and reducing complexity.

Why Serverless Architecture?

  1. Cost Savings: With serverless, you only pay for the actual usage of your functions and services, rather than paying for idle resources.

  2. Scalability: Serverless platforms automatically scale your functions based on the incoming workload. Whether you have 10 users or 10,000 users, the platform dynamically allocates resources to handle the traffic, ensuring optimal performance and eliminating concerns about handling sudden spikes in usage.

  3. Developer Productivity: Serverless architecture allows developers to focus on writing application logic rather than managing infrastructure. By offloading server management and operations to the cloud provider, developers can deliver features faster, iterate quickly, and improve overall productivity.

  4. High Availability: Serverless platforms provide built-in fault tolerance and high availability. The underlying infrastructure ensures that functions are distributed across multiple data centres, reducing the risk of single points of failure and ensuring robustness.

Serverless Architecture with Firebase

Firebase

Firebase, developed by Google, is a prominent platform that empowers serverless computing, specifically designed for mobile and web application development. In this article, we will explore the Firebase Emulator Suite, a robust toolkit that equips developers with the ability to locally develop and test their Firebase applications. We will discuss the process of setting up the Firebase Emulator and constructing a Contact Management System utilizing Firebase Cloud Functions.

Contact Management System with Firebase

Before we begin, ensure that you have the following prerequisites in place:

  1. Node.js installed on your machine.
  2. JDK installed on your machine.
  3. Basic knowledge of Firebase concepts and the Command Line Interface (CLI).

1.Setting up Firebase Emulator and initialising Firebase SDK

Firstly, you need to ensure that you have the Firebase CLI (Command-Line Interface) installed. To do so, open your terminal or command prompt and run the following command:

npm install -g firebase-tools
Enter fullscreen mode Exit fullscreen mode

install firebase-tools

To Check the version of Firebase installed, you can use the following command:

firebase ––version
Enter fullscreen mode Exit fullscreen mode

Next, you need to login to your Firebase account. Typing the following command will redirect you to a login page, where you’ll be prompted to login.

firebase  login
Enter fullscreen mode Exit fullscreen mode

Now, you need to make a new project in your Firebase Console. For this article, we have created a project contact-manage.
Create a new directory for your project and navigate into it. For the next step, initialize Firebase in your project folder using the following command:

firebase  init
Enter fullscreen mode Exit fullscreen mode

You will be asked to select the Firebase features you want to set up for your directory. Press Space to select features, and then press enter. For this project, we have only chosen the ‘function’ feature. You will also be asked to choose a project and a language to write the cloud functions. Select the required options to complete the initialization process.

firebase init

The Firestore emulator grants you access to a local version of your Firestore database, resembling the view you would see in the Firebase Console. However, the emulator offers faster performance compared to the online console.To install the Emulators for your app, type in the following command:

firebase init emulators
Enter fullscreen mode Exit fullscreen mode

Then, you will be prompted for setup questions in the terminal. First, it will ask you to pick which emulators you want to use. In this article, we’ll cover Authentication, Firestore, and Cloud Functions.
After you pick the emulators you want to use, it will then prompt you to pick the ports they’ll run on. We will just go ahead with the defaults.
It will also ask you if you want to use the emulator’s UI, pick yes, because we’ll be using that to review and interact with our firebase application.

firebase init emulators

Now, to test that everything is set up, open the terminal again in your project’s root folder, and start the emulator using:

firebase emulators:start
Enter fullscreen mode Exit fullscreen mode

It will start your emulators and show you the emulators' information in the terminal.

emulators' information

After starting the Firebase Emulator, you can access its user interface by navigating to localhost:4000 in your web browser. The UI provides a dashboard displaying all the active emulators you have configured. By clicking on a specific emulator, you will be directed to its corresponding page.

emulator ui

2. Writing Cloud Functions

Our app will allow the user to create a new contact, fetch all the saved contacts, delete a contact, update a contact and finally, search for a contact.

Open the index.js file and start with initialising the Firebase Admin SDK with the following line of code:

 admin.initializeApp();
Enter fullscreen mode Exit fullscreen mode

Reference to the Firestore collection ‘contacts’ for storing all the contacts:

const contactsCollection = admin.firestore().collection('contacts');
Enter fullscreen mode Exit fullscreen mode

We will now define all the required functions.

Create Contacts Function

Our first function is createContacts. This function creates a new contact in the Firestore database. It listens for an HTTP request and expects the contact details in the request body. It uses the contactsCollection reference to add the contact to the Firestore collection. Upon successful creation, it responds with the contact data and a status code of 201.

exports.createContact = functions.https.onRequest(async (req, res) => {
  try {
    const newContact = req.body;
    const contactRef = await contactsCollection.add(newContact);
    const contactId = contactRef.id;
    const contact = await contactRef.get();
    res.status(201).json({id:contactId, ...contact.data()});
  } catch (error) {
    res.status(500).send('Error creating contact');
  }
});
Enter fullscreen mode Exit fullscreen mode

Get Contacts Function

Next, we will create a function called getContacts. This function retrieves all contacts from the Firestore database. It listens for an HTTP request and fetches all documents from the contactsCollection. It then maps the document data and responds with an array of contact objects and a status code of 200.

exports.getContacts = functions.https.onRequest(async (req, res) => {
  try {
    const contactsSnapshot = await contactsCollection.get();
    const contacts = contactsSnapshot.docs.map((doc) => doc.data());
    res.status(200).json(contacts);
  } catch (error) {
    res.status(500).send('Error retrieving contacts');
  }
});
Enter fullscreen mode Exit fullscreen mode

Update Contact Function

Our next function is updateContacts. This function updates an existing contact in the Firestore database. It expects the contact ID in the request URL and the updated contact details in the request body. Using the contactsCollection reference, it locates the specific contact document and updates it with the new information. Upon successful update, it responds with a success message and a status code of 200.

exports.updateContact = functions.https.onRequest(async (req, res) => {
  try {
    const contactId = req.params.contactId;
    const updatedContact = req.body;

    await contactsCollection.doc(contactId).update(updatedContact);
    res.status(200).send('Contact updated successfully');
  } catch (error) {
    res.status(500).send('Error updating contact');
  }
});
Enter fullscreen mode Exit fullscreen mode

Delete Contact Function

To delete a contact from the Firestore database, we will create a function deleteContact. It listens for an HTTP request with the contact ID in the URL. Using the contactsCollection reference, it finds the corresponding document and deletes it. If successful, it responds with a success message and a status code of 200.

exports.deleteContact = functions.https.onRequest(async (req, res) => {
  try {
    const contactId = req.params.contactId;
    await contactsCollection.doc(contactId).delete();
    res.status(200).send('Contact deleted successfully');
  } catch (error) {
    res.status(500).send('Error deleting contact');
  }
});
Enter fullscreen mode Exit fullscreen mode

Search Contacts Function

Finally, we will create a function searchContacts. This function searches for contacts by name in the Firestore database. It expects a search term as a query parameter in the request URL. It queries the contactsCollection using the where method to find contacts with names greater than or equal to the search term. It then maps the query snapshot and responds with an array of matching contacts and a status code of 200.

exports.searchContacts = functions.https.onRequest(async (req, res) => {
  try {
    const searchTerm = req.query.q;
    const querySnapshot = await contactsCollection.where('name', '>=', searchTerm).get();
    const contacts = querySnapshot.docs.map((doc) => doc.data());
    res.status(200).json(contacts);
  } catch (error) {
    res.status(500).send('Error searching contacts');
  }
});
Enter fullscreen mode Exit fullscreen mode

3. Triggering functions on auth events

Create User Function

We will now export a function named addUser. The core functionality of this function revolves around the onCreate event trigger. This event is fired whenever a new user account is created in Firebase Authentication. Upon activation, the function logs a message.
The function takes a single argument named user. This user object holds crucial information about the newly created account, including properties like uid and email.To provide yourself with insight into the function's execution, you can log a message to the Firebase Cloud Functions logs.

exports.addUser = functions.auth.user().onCreate((user)=>{
  console.log(`${user.email} has been created...`)
  return Promise.resolve
})
Enter fullscreen mode Exit fullscreen mode

Delete User Function

We will next define the delUser function, which will serve the purpose of deleting a user from our app. The core functionality revolves around utilising the onDelete event trigger, which is triggered whenever a user account is deleted from Firebase Authentication. Once activated, the function proceeds to execute specific tasks related to user deletion.
The function accepts a single argument named user. This user object encapsulates pertinent information about the deleted account, including attributes such as email and uid.

exports.delUser = functions.auth.user().onDelete((user)=>{
  console.log(`${user.email} has been deleted...`)
  return Promise.resolve
})
Enter fullscreen mode Exit fullscreen mode

4. Testing the Functions

We will now see how we perform operations using the functions we created. To make HTTP requests, you will require the URLs of the functions you have created so far. These URLs will be displayed on the terminal/command prompt when you create the functions.

terminal

You can add a new contact in the database using the createContact function. Open your terminal/command prompt and use the curl command to make a POST request to the URL of the createContact function. Pass the contact details in the body.

curl -X POST -H "Content-Type: application/json" -d '{
    "name": "hailey",
    "email": "hailey34@example.com",
    "phone": "5432xxxxx0"
  }' YOUR_FUNCTION_URL

Enter fullscreen mode Exit fullscreen mode

This will add a new document in the contacts collection in our Firestore database. You can check this by navigating to the emulator's UI running on localhost:4000.

terminal

The next step is to test the authentication functions. We will take the addUser function as an example. Navigate to the Authentication section of the Emulators' UI and click on the Add User button. Fill in the required fields and add the user.

terminal

Adding this user will trigger our addUser function.

terminal

Challenges and Considerations

While serverless architecture offers numerous benefits, it's important to consider the following challenges:

  1. Cold Start Latency: The first invocation of a function may experience a delay known as a "cold start" as the serverless platform provisions the necessary resources. Although the platforms are continuously improving cold start times, it's crucial to optimize your code and leverage techniques like connection pooling to mitigate this latency.

  2. Vendor Lock-In: Adopting serverless architecture may tie your application to a specific cloud provider's platform and services.

  3. Performance Monitoring and Debugging: As serverless abstracts away infrastructure management, monitoring and debugging can become more challenging.

In addition to these considerations, a number of other drawbacks have surfaced. These came to light when Amazon Prime recently declared that it would stop using serverless technology.
Scaling limitations, potential cost inefficiencies, issues with data-intensive operations, and constraints related to real-time processing are some scenarios that can pose as hurdles. It is also important to align architecture choices with specific project requirements, and caution must be taken against extreme stances on architecture.
A balanced and context-aware approach is essential for making effective architectural decisions.

Alright, so let's check it out – this whole serverless thing has totally shaken up the game when it comes to building apps. It's like this new era where you can develop your stuff without worrying about servers and all that complications.

Instead of pulling your hair out over server management, you can dive right into crafting your app's core. You'll be dropping features left and right, making users happy because you're lightning-fast at giving them what they want.

Thank you for sticking with us till the end. We hope you had a great time reading this article!


Project Github repository :

Contact-manager

A contact management system where users can store and manage their contacts.

This project uses Firebase Cloud Functions to handle CRUD operations for contacts, implements search functionality, and allows users to update contact details.

Project collaborators :

Do visit our website and connect with us

GitHub

Facebook

LinkedIn

Instagram


terminal

terminal

Top comments (5)

Collapse
 
sankeerth627 profile image
Sankeerth suravaram

Firebase is just awesome even now supabase an open-source serverless architecture is about to release right I'm just amazed

Collapse
 
sayan650 profile image
Sayan Paul

Firebase is awesome thing to work with as a learner.

Collapse
 
rborajov profile image
Roschek Borajov

Hello there.
I found this post to be very much misleading as there are couple of terms which are meaningless in the context of Firebase. I have been working with Firebase, Cloud Native Architecture Refinement and Automation Services for the last 10 years.

The functions mentioned in BaaS and FaaS should be refined. The explanation here is out of context. The contact management system mentioned in the Github does not forecast the use of BaaS and FaaS. Please don't mislead developers on such resourceful platforms.

Also, it never uses the concept of emulators in the repository outreach. Please know about the basics of emulators before you deliver thr content. Emulators are never used for redirection and single valued dependencies. Hope that's clear.

Hope it helps you in the future. And hope you correct your article. Nice attempt. Hope yoh learn about Firebase more efficiently in the future. Keep trying !!

Collapse
 
sudhidutta7694 profile image
Sudhi Sundar Dutta

The enormous functionalities that Firebase provides accompanied by its ease of use as compared to other databases is really quite impressive.

Collapse
 
dipayandas24 profile image
Dipayan Das

Firebase is just amazing to start and work with beginner friendly learning...