Cloud Functions

Photo by Luca Bravo on Unsplash

Cloud Functions

·

4 min read

What are cloud functions? How do they work? Let’s start with how normal functions behave, for instance, in Javascript;

function sum(num1, num2) {
   return num1+num2
}
sum(8, 7)

In the code above, we have a function called sum with 2 parameters - num1 and num2 which then returns the addition between two given numbers. To utilize the function, we need to call it, sum(8,7)
Different platforms provide cloud functions capabilities such as Google Cloud Functions, AWS Lambda, Convex Functions, and many others. For our case study, we’ll use Cloud Functions for Firebase.
Cloud Functions for Firebase provides the capability to execute backend code automatically in response to events. These events can be triggered by background events, HTTPS requests, the Admin SDK, or Cloud Scheduler jobs.
An example that we’ll for our case study can be - sending notifications to the user when an event such as user registration - occurs.

Functioning Mechanism

Once a function is written successfully, it must be deployed to the cloud functions runtime for use. During deployment, the Firebase CLI takes all the code related to that function, segregates each function into separate containers, and Google’s servers begin to manage the function.

Cloud Functions can be invoked directly via an HTTP request or in response to an event. When this occurs, Cloud Functions initiates a server instance for the function in the cloud that activates and executes the function in response to these triggers. Cloud Functions then oversees this function and ensures that the created instance remains active until its promise is fulfilled. As the usage of our application fluctuates, Google adjusts by automatically scaling the server instances required to execute these functions.

Case study - Certificate Generator

Say we want an instance when a student finishes a course, they are issued the course certificate via email.

import * as functions from "firebase-functions"
import * as fs from "fs"
import * as nodemailer from "nodemailer"
import * as pdfLib from "pdf-lib"

const gmailEmail = functions.config().gmail.email
const gmailPassword = functions.config().gmail.password

const transporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: gmailEmail,
    pass: gmailPassword,
  },
})

export const sendEmail = functions.firestore
  .document("courseCompletion/{userId}")
  .onCreate(async (snap, context) => {
    const newValue = snap.data()
    const firstName = newValue.firstName
    const email = newValue.email

    // Load the certificate PDF as a buffer
    const certificatePath = "./cert.pdf"
    const certificateBuffer = fs.readFileSync(certificatePath)

    // Create a new PDF with the user's name
    const pdfDoc = await pdfLib.PDFDocument.load(certificateBuffer)
    const page = pdfDoc.getPages()[0]
    const { width, height } = page.getSize()
    const fontSize = 48
    const font = await pdfDoc.embedFont(pdfLib.StandardFonts.TimesRomanItalic)
    const textWidth = font.widthOfTextAtSize(firstName, fontSize)
    page.drawText(firstName, {
      x: (width - textWidth) / 2,
      y: height / 2.7,
      size: fontSize,
      font,
      color: pdfLib.rgb(0, 0, 0),
    })

    // Convert the PDF to a buffer
    const pdfBytes = await pdfDoc.save()

    const mailOptions = {
      from: "sender@gmail.com",
      to: email,
      subject: "Course Certificate",
      text: `Hello ${firstName},\n\nCongratulations on completing the course.`,
      attachments: [
        {
          filename: "cert.pdf",
          content: Buffer.from(pdfBytes),
        },
      ],
    }

    try {
      await transporter.sendMail(mailOptions)
      functions.logger.log(`Email sent to ${email}`)
      // console.log(`Email sent to ${email}`)
    } catch (e) {
      functions.logger.log(`Error sending email to ${email}`)
    }
    return null
  })

Let's look at this step by step;

  1. The necessary modules are imported, including firebase-functions for creating the cloud function.

  2. Email config - the Gmail email and password are retrieved from the Firebase configuration. Used for creating the nodemailer credentials that will be used to send emails.

  3. A cloud function that's exported that triggers when a new document is created in the courseCompletion collection in Firestore.

  4. The user's data is retrieved which is now used in the email.

  5. Then we get the PDF certificate template being loaded from a file - and the user's name is added and other details such as the course name.

  6. The email is now composed and sent with the new PDF certificate as an attachment.

This function runs automatically whenever a user completes a course.

This is just one of the many use cases for Cloud Functions. They can be used to handle a wide range of tasks, from sending notifications, processing data, integrating with third-party services, and much more.

Cloud Functions offer a powerful way to run server-side code in response to events, without the need for a dedicated server. They provide a scalable solution to handle varying loads and can be used across various platforms such as Google Cloud Functions, AWS Lambda, and Convex Functions.

So, whether you’re a seasoned developer or just starting, it’s a great time to start exploring what Cloud Functions can do for you. Happy coding!