How to deploy a cloud function
What it is and why you might need it

General description

Cloud functions are typically small executable code snippets with a "pay as you go" policy. There is no server for you to manage and usually they come with features like "automatic scaling", "security measurements" and more.

Why would you need cloud functions?


Since the rise of JAM stack websites and applications that are rendered server-side (for example with (e.g. with Gatsby.js or Next.js) the question often arises, what to do if the situation arises if you find yourself in a situation where you need a server to run a few heavyweight tasks or processes, which are either not feasible in the browser or would be out of place.


You could of course set up your own server and run it as a separate process. The would be legitimate depending on the use case. In many use cases (e.g. sending an email) the whole thing would be the whole thing would be overkill.


Cloud functions to the rescue

Not only would an own server be another entity, which needs maintenance and care, but also not always justified in terms of price. So we need something better. Cloud functions are our friend and helper. The small functions can be easily hosted at a Cloud Provider of trust and can be called whenever they are needed.

Let's see it in action

For this, the following scenario to stay in the jam stack. Let's assume you want to host a Next.js website. This website of course uses all the cool features of Next.js 12, including the built-in image optimization. With this you can achieve these cool "blur" effects when loading an image for the first time. (which, by the way, is also the case on this website - you can see it if you want to troll through the portfolio).

To use the built-in image optimization, images should be hosted within the website directory. If this is not the case (e.g. external images with a CMS) then the blur will only work if you provide a blurDataUrl as a property that represents a base64 string of a reduced image.


For this a cloud function is perfect. You could use the cloud function during the build process to generate just such a Base64 Data Url for each image. And that's exactly what we are doing now.

Example setup

I said you can use a provider of your choice. I use Google Cloud, simply because of the intuitive management.

First, login to google cloud under https://cloud.google.com.

Once you are logged in, switch to your cloud console and go to cloud functions. You can also use this link: https://console.cloud.google.com/functions/add


There you can click on the button to add a new cloud function, which will bring you to the setup screen. From here the base information for your google cloud function can be entered. This includes information like the name, region and also type of trigger, that you would like to use. In our use case a simple HTTP Trigger is sufficient. This will give us an Endpoint which we can hit whenever we want the cloud function to run.

cloud function setup
Image 1: Setting up the cloud functions base information

Environment Setup

After you have set up your base information you can also enter environment variables or other infrastructural settings. This includes the max execution time or the memory which can be allocated during the processing.

Depending on the expected load, i would recommend to leave the "Autoscaling" Option on 0 minimum instances.

cloud function setup
Image 2: Cloud function infrastructure setup

A look at the code

The next screen will let you enter the source code. You can write directly in the cloud editor or locally and copy it over. As shown below, an implementation is quite simple


const fetch = require("node-fetch");
const sharp = require("sharp");

/**
 * @description fetch the image and return a buffer from it
 * @param {string} imgUrl url of image
 * @returns {Promise<Buffer>} buffer of image
 */
const getBufferFromRemote = async imgUrl => {
	const blurDataURL = await fetch(imgUrl);

	const buffer = await blurDataURL.buffer();

	return buffer;
};

/**
 * @description takes an image url and returns a base64 string
 * @param {string} imgUrl the image url
 * @param {number} width the image output width
 * @param {number} height the image output height
 * @returns {Promise<string>} the image url as base64 data url
 */
exports.generateBase64DataUrl = async (req, res) => {
	try {
		res.set("Access-Control-Allow-Origin", "*");
		res.set("Access-Control-Allow-Methods", "POST, OPTIONS");
		res.set("Access-Control-Allow-Headers", "*");

		if (req.method === "OPTIONS") {
			res.status(204).send("");
			return;
		}

		let { body } = req;

		const { imgUrl, width, height } = body;

		if (!imgUrl) {
			throw new Error("imgUrl is required");
		}

		if (!width) {
			throw new Error("width is required");
		}

		if (!height) {
			throw new Error("height is required");
		}

		// fetch image as Buffer
		const buffer = await getBufferFromRemote(imgUrl);

		// resize image with the sharp package
		const resized = await sharp(buffer, {}).resize(width, height).toBuffer();

		// create base64 string from resized image
		res.status(200).send({
			ok: true,
			dataUrl: `data:image/png;base64,${resized.toString("base64")}`,
		});
	} catch (error) {
		res.status(500).send({ ok: false, error: error.message });
	}
};

Explanation

Now, as you can see in the above code example, we are exporting a single entrypoint generateBase64DataUrl. This is the function that will be called once the endpoint of our cloud function was hit.

First we make sure that we return immediately in case there was an OPTIONS request, which will not contain any data that interests us. Afterwards we are destructuring the body from the request object.


The next few if statements are validating the data. If the data is in the shape that we want to receive, we create a Buffer from the Imageurl that was transmitted in the request body.


The function getBufferFromRemote fetches the image and returns a buffer from that image. We are then using the sharp plugin to resize the image to a small scale (like 10x10 px) and create a base64 data url which will be returned from the cloud function


Some other use cases

The use cases are endless. But lets take a quick look at a few examples to get you started using cloud functions for your next projects


  • Sending Emails with Nodemailer or providers like mailgun
  • tracking and analytics
  • storing targeted datasets into a database
  • and many more


Conclusion:

In any case, cloud function are not that different from what you would expect to run on a "normal" server. The fact that they are so cost effective and fast to set up is a huge bonus for many use cases. If you can determine a small task that you would have to execute serverside, likely a cloud function is the right choice.