Firebase Functions to Build a Serverless CRUD App
Tags: webdev, javascript, firebase, crud
Published: 2023-06-24 23:28:47

![](https://cdn-images-1.medium.com/max/1600/1*sYhkip0nV3VKJjYaGeBQFA.png align="left")

[Firebase](https://firebase.google.com/) is a powerful backend service provided by Google that speeds up Web Development by providing a BaaS (Backend-as-a-service) infrastructure. Firebase allows Engineering teams to quickly build out and prototype applications without the need to worry about common backend services like authentication, authorization, database provision, task schedulers (thank you cloud functions!), and more! Some of the features listed above are different services within the Firebase console — e.g Firestore is Firebase’s database service.

Firebase can be integrated with a web or mobile application using any of the available SDKs. In this project, we’ll be using the Firebase JavaScript SDK.

In this article, we’ll look at some of the most common functions you’ll need to build out a Backend using Firebase’s Firestore database and auth service. Think of this as a Cheat sheet to avoid reading the firebase docs.

### Getting Started with Firebase

To get started setting up your firebase service, simply head over to [https://firebase.google.com/](https://firebase.google.com/), make sure you’re signed in with your Google account, and hit the **Get started** button.

On the **Welcome to Firebase** screen, click **Create Project** to spin up a new firebase project. Give your project a name, accept the terms and conditions and let’s dance! You’ll be brought to the firebase console. Next, select your project from the list of projects and click **Firestore Database** to the left of your dashboard. From here, we can manage everything to do with our Databases.

By default, Firebase allows anyone to read and write from your database for a period of 30 days — as long as they have your keys. You can see your database rules by going under the **rules** tab on the Firestore page in your firebase console. Make sure to edit these rules when you’re ready to go to PROD.

### Adding Firebase to your Project

To add Firebase to your project, you’ll need a set of keys. Click on the gear icon next to **Project Overview** to access the keys for your project.

![](https://cdn-images-1.medium.com/max/1600/0*-T3SMkkXsKJV6xrY.png align="left")

We’ll be integrating firebase into our React project. To set up Firebase in your project, run the command;

```plaintext
npm install firebase
```

This will add the Firebase SDK to your project. Create a `.env` file in the root directory of your project and set the following variables. You can get the values from the Project Settings section above.

```plaintext
apiKey= YOUR_KEY
authDomain= YOUR_KEY
projectId=YOUR_KEY
storageBucket=YOUR_KEY
messagingSenderId=YOUR_KEY
appId=YOUR_KEY
```

With your environment variables set up, we’re ready to start adding functions.

### Setup Firebase in Your Codebase

We’ll now run through getting Firebase setup within our app. In the root directory of your project, create a folder named utils and a file called **firebase.js**. You can follow whatever directory structure you prefer but I like to setup my projects like this.

In your **firebase.js** file, add the following lines. We start off by importing all the functions we need from within the firebase module.

```plaintext
// initialize firebase
import { initializeApp } from 'firebase/app'
```

```plaintext
// firebase auth service
import {
  getAuth,
  signInWithEmailAndPassword,
  onAuthStateChanged,
  updateProfile,
  signOut,
createUserWithEmailAndPassword
} from 'firebase/auth'

```

```plaintext
// firebase DB service
import {
  collection,
  getFirestore,
  addDoc,
  getDocs,
  updateDoc,
  doc,
  getDoc,
  setDoc,
  arrayUnion,
  deleteDoc
} from 'firebase/firestore'
```

```plaintext
const firebaseConfig = {
  apiKey: process.env.apiKey,
  authDomain: process.env.authDomain,
  projectId: process.env.projectId,
  storageBucket: process.env.storageBucket,
  messagingSenderId: process.env.messagingSenderId,
  appId: process.env.appId,
}
```

```plaintext
// initialize firebase
export const app = initializeApp(firebaseConfig)
```

```plaintext
// connect to firebase auth with your credentials
export const auth = getAuth(app)
```

```plaintext
// connect to firebase db with your credentials
const db = getFirestore(app)
```

On to the next!

### Auth

What’s one thing every app must have? You guessed it! Auth!

Firebase allows you to use sign-in providers like Google, Twitter, Microsoft or Facebook to allow your users sign in with their accounts on other platforms. To set this up, simply head over to the **Build** tab on your Firebase console, click **Authentication** and then the **sign in** method tab.

![](https://cdn-images-1.medium.com/max/1600/0*20FGMbNrdnt_i13P.png align="left")

In this article, we’ll be keeping it simple and using the E-mail and password auth provided by Google. To get started, under the **Users** tab, click **Add user**.

![](https://cdn-images-1.medium.com/max/1600/0*EMVQfEMP50CoCdWb.png align="left")

This allows you to create a login for users on your platform from inside Firebase itself. To allow users sign up from within your UI, use the following block of code.

```plaintext
const register = async ({ email, password }) => {
  try {
    const { user } = await createUserWithEmailAndPassword(auth, email, password)
    return user
  } catch (e) {
    return false
  }
}
```

For your login flow, call the `signInWithEmailAndPassword` provided by Firebase, like below.

```plaintext
const login = async ({ email, password }) => {
  try {
    const { user } = await signInWithEmailAndPassword(auth, email, password)
```

```plaintext
    return user
  } catch (e) {
    return false
  }
}
```

To check if a user is signed in, use;

```plaintext
const isUserSignedIn = async () => {
  onAuthStateChanged(auth, (user) => {
    if (user) {
      // get signedIn user
      const uid = user.uid
      console.log(user)
      return uid
    } else {
      return false
    }
  })
}
```

To sign out a user from your service;

```plaintext
const signOutUser = async () => {
  await signOut(auth)
}
```

To update a user’s metadata, use;

```plaintext
const updateUserProfile = async ({ displayName, photoURL }) => {
  try {
    await updateProfile(auth.currentUser, {
      displayName,
      photoURL,
    })
  } catch (error) {
  }
}
```

### Adding new Collections and Documents to Firestore

Firebase is a No-SQL database. This means that the Database structure is a little bit different from conventional SQL databases. For example, while SQL databases are based off the idea of Tables and Columns, No-SQL databases use documents and collections to structure data. Collections can be likened to tables and documents to columns — they’re not like for like though and shouldn’t be considered as such.

Let’s create a User’s collection in our DB. To create a new collection, we’ll simply add a document to the collection in our codebase. Firebase is intelligent enough to create the collection and a document at the same time even if the collection does not already exist.

```plaintext
// take in the user's details from the UI
const addNewUser = async ({ phoneNo, name, email, address, cars = '' }) => {
```

```plaintext
  try {
    // add a new Doc to the User's Collection
    const userRef = await addDoc(collection(db, 'users'), {
      phoneNo,
      name,
      email,
      address,
      cars
    })
```

```plaintext
    console.log('Document written with ID: ', userRef.id)
  } catch (e) {
    console.error('Error adding document: ', e)
  }
}
```

### Getting all the Data in a Firestore Collection

If we want to get all the users in our database for example, we can use the `getDocs()` function.

```plaintext
const getCollection = async () => {
  try {
    const users = []
```

```plaintext
    const querySnapshot = await getDocs(collection(db, 'users'))
    querySnapshot.forEach((doc) => {
      users.push({ user: doc.data(), docId: doc.id })
    })
```

```plaintext
    return users
  } catch (error) {
    console.log(error)
  }
}
```

### Update a Record in Firestore

If you have a user in the DB already, you can update their records in the DB.

```plaintext
// Update the user's details
const updateUserPhoneNo = async ({ phoneNo, user }) => {
```

```plaintext
  try {
    const userRef = doc(db, 'users', [USER_DOCUMENT_ID])
```

```plaintext
    // Update the User's Collection
    const userRef = await updateDoc(userRef, {
      phoneNo,
    })
```

```plaintext
    console.log('Document written with ID: ', userRef.id)
  } catch (e) {
    console.error('Error adding document: ', e)
  }
}
```

For the block of code above to work, you’ll need to know the **USER\_DOCUMENT\_ID** to look up the user and update the user’s records.

Firebase will automatically generate a **Document ID** for data written to the database. While writing to the DB, this ID is generated after the document has been written which may make it a little difficult to update the record in the future. To prevent this, I prefer to use a unique ID to identify unique users in my database and subsequently use that ID to look up a user’s records in my database. You can use the popular [UUID](https://www.npmjs.com/package/uuid) npm package to generate these IDs.

For example, we can change our function to add a user to the following;

```plaintext
// take in the user's details from the UI
const addNewUser = async ({ phoneNo, name, email, address, cars = '' }) => {
```

```plaintext
  const userId = uuid_v4() // generate the userId
  const userRef = doc(db, 'users', userId) // use the userId generated to create a docId
  const data = {
      phoneNo,
      name,
      email,
      address,
      cars,
      userId // save the userId to the user record
    }
```

```plaintext
  try {
    // add a new Doc to the User's Collection
    await setDoc(userRef, data, { merge: true })
    console.log('Document written with ID: ', userRef.id)
```

```plaintext
  } catch (e) {
    console.error('Error adding document: ', e)
  }
}
```

This would mean that our update function from earlier will look like;

```plaintext
// Update the user's details
const updateUserPhoneNo = async ({ phoneNo, user }) => {
```

```plaintext
  try {
    const userRef = doc(db, 'users', user.userId) // use the userId to find the user in the DB
```

```plaintext
    // Update the User's Collection
    const userRef = await updateDoc(userRef, {
      phoneNo,
    })
```

```plaintext
    console.log('Document written with ID: ', userRef.id)
  } catch (e) {
    console.error('Error adding document: ', e)
  }
}
```

Note that **addDoc()** and **setDoc()** are slightly different in the way they work. `addDoc` will automatically generate a Document ID for your document while writing to the DB while `setDoc` allowing you to specify the Document ID you’ll like to use. For writing data that you’ll want to look up later, using `setDoc` is advisable to allow for easier look-up.

### Update an array Record in Firestore

If you have a record in your database that takes in an array and you need to update that record, use the `array_union` function. For example, imagine that our user has some cars in his Garage.

```plaintext
// Update the user's details
const updateUserPhoneNo = async ({ phoneNo, carName }) => {
```

```plaintext
  try {
    const userRef = doc(db, 'users', [USER_DOC_ID]) // USER_DOC_ID is the userId if you followed the setDoc example
```

```plaintext
    // Update the User's Collection
    const userRef = await updateDoc(userRef, {
      cars: arrayUnion({
          carName: carName,
      }),
    })
```

```plaintext
    console.log('Document written with ID: ', userRef.id)
  } catch (e) {
    console.error('Error adding document: ', e)
  }
}
```

### Deleting a Document in Firestore

```plaintext
const deleteUser = async ({ user }) =>{
  try {
    const userRef = doc(db, 'users', user.userId)
    await deleteDoc(doc(db, "users", userRef));
```

```plaintext
  } catch (e) {
    console.error('Error adding document: ', e)
  }  
}
```

### Rounding Up

With the functions above, you can create your own application by using Firebase as a backend service. The functions above list all the CRUD operations you need to create your own backend service. To summarise;

`setDoc` or `addDoc` allows you to CREATE a new firestore document/collection.

`getDoc` allows you to READ the data within your firestore collection

`updateDoc` allows you to UPDATE a document within a firestore collection

`deleteDoc` allows you to DELETE a document within a firestore collection.

For more information, the [Firebase docs](https://firebase.google.com/docs/firestore) provide a complete resource for all firestore functions and features.