Search:   Dictionary All Posts
Store Your Knowledge at the Brain Bank!

Firebase Cloud Functions - The Server!

By Jamie in Lessons / Programming - React  1.29.19  (Source)
Summary - Firebase cloud functions are functions stored on the firebase server. They have a similar concept to an express server. They are meant to listen for things that happen on the server and then send responses to the frontend.
The concept here is that you want to create functions that run when triggered. It could be an http request that triggers the function, or it could be something that happens in one of the collections in the database, like a new user registers, or a new post is added.  The functions can also be though of smart listeners, but they are listening for things on the server, not things on the frontend like a user click. or input change.

Instructions for setting up can also be found within Firebase.

The Server Setup
1. npm install -g firebase-tools
2. firebase login
3. firebase init
4. do not run firebase deploy until you have built what you needed to build

firebase init will install some folders in your project (see the source link for details on the answers to the questions when running firebase init) the functions folder is where we create new cloud functions. Later we will deploy them to firebase.
Don't follow one of source link's instructions... instead of dist, use build. When react build is created it will write to that folder

/functions/index.js
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.intializeApp(functions.config().firebase)

exports.helloWorld = functions.https.onRequest((request, response) => {
    response.send('Hello, World!')
})

That's it. Now when you deploy, in the terminal it will give you the URL of this new function which will be hosted in the firebase cloud. This is for an http request, meaning, when a user goes to the URL, a response will be sent.

Function Triggers (more...)
But there is a much cooler type of function trigger we will look at now. Let's say you want to add data to a collection, after other data was added to a different collection. For instance, you have a projects collection and a users collection. You want to create a notifications collection which will save when a project or user has been created. It will store when it happened, as well as who did it. Then we can have it update on the frontend to let users know - New User Joined, or New Project Created.

So first, we create a function that will add data to this notifications collection.

const createNotification = notification => {
    return admin.firestore().collection('notifications')
        .add(notification)
        .then(() => console.log('notification added')
}

exports.projectCreated = functions.firestore
    .document('projects/{projects}')
    .onCreate(doc => {
        const project = doc.data()
        const notification = {
            content: 'Added new project!',
            user: `${project.authorFirstName} ${project.authorLastName},
            time: admin.firestore.FieldValue.serverTimestamp()
        }
        return createNotification(notification)
    })

exports.userJoined = functions.auth.user()
    .onCreate(user => {
        return admin.firestore().collection('users')
            .doc(user.uid).get().then(doc => {
                const newUser = doc.data()
                const notification = {
                    content: 'Joined the party!',
                    user: `${newUser.firstName} ${newUser.lastName}`,
                    time: admin.firestore.FieldValue.serverTimestamp()
                }
                return createNotification(notification)
        })
    })

Explanation of Above Code....
Many of the above functions are built in to Firebase/Firestore and you simply have to reference the documentation but let's try to explain it a bit.

exports.projectCreated = functions... - when deployed, this will create 'projectCreated' as a cloud function in Firebase. If it already exists it will overwrite it with this latest code. It has a property called firestore, which has a method called document, with the a path to the desired database collection as the parameter.

.onCreate() is a method that says, watch the collection specified for when anything new is created and return the object. We name the object 'doc' and pass it into an anonymous function. We set a project const equal to 'doc.data()' - .data() is a built in function that gets us the object of the object of the new document. Then we create a 'notification' object. We then return a function call to our createNotification function with the notification passed in. 

exports.userJoined = functions... will create another cloud function in firebase when deployed. instead of getting the firestore, we get the auth, which is where new users are created. Then we call the built in user() function which tells Firebase to watch the user collection of auth. Then we chain .onCreate() which tells Firebase to watch that user collection for a newly created user. When it gets one it will return the user, which we then use as a parameter for another anonymous function. We then need to get information from the new user's profile, using the newUser's id. We need to put a return statement first in the .onCreate() method because we need it to return this data first, which we will use to add to our notification object.

admin.firestore().collection('users').doc(user.uid).get() is the function that will go to our firestore 'users' collection and get the document with the passed in user.uid. That is an async call so we need a .then, which receives the document, then we do the same as we did in the first cloud function but with a different message. Then, of course, we call the function to add this to the notifications collection.


Retrieving this Data
Because all we are doing now is getting data from this newly formed 'notifications' collection, we add data to our frontend the same way we would otherwise retrieve data from the firestore.

That guide is here...