Image Resizing with Go and Cloud Functions

Go + Serverless = ❤️

Google Cloud Platform now supports Go 1.11 for Cloud functions. Go and Serverless are 2 things I’m very excited about these days so I decided to give this new GCP feature a try and build a basic Image Resizer in pure Go using the disintegration/imaging package.

Resizing gophers

Sometimes you just have gopher images that are too large to display on your website. They would eat up the precious bandwidth of your users ! Like this massive one:

Big gopher generated using gopherize.me

So we’ll be transforming it into this smaller, more reasonable gopher:

Small gopher

What we’ll build in order to achieve this is a cloud function with an endpoint that can be called in the following way:

https://{region}-{project-name}.cloudfunctions.net/ResizeImage?url={url}&height={height}&width={width}

We just send an HTTP GET request with our image url, the desired width and height and we receive an image in JPEG format in the HTTP response body.

Setup

To follow along, you’ll need to have Go 1.11 installed on your dev box, a Google Cloud Platform account and the gcloud command line tool setup.

I’ve setup a github repo if you would like to browse it/clone it locally and test as you’re reading.

The ResizeImage cloud function

The cloud function we’ll use is an HTTP function. This cloud function type gives us an HTTPS endpoint for our code without needing an extra API Gateway so that’s pretty convenient for our use case. The other cloud function type: Background functions can be triggered by events such as Pub/Sub or Cloud Storage events. We won’t be using this today but it could come in handy for other tasks such as caching our images, cleaning up the cache periodically etc. I might write about Background functions in a future article.

The ResizeImage function needs to do the following things:

Parse the Query string into url, height and width

Fetch the original image

Resize the image

Encode the output image to Jpg

Write the encoded output image to the HTTP Response stream

To keep things simple I’ve included all the code in a single file. The filename doesn’t matter.

I’ve also included a go.mod file with the dependencies as that’s supported.

To push all this to the cloud, we use the gcloud tool and specify the name of the function that we want to deploy. In this case it’s this go function:

ResizeImage(w http.ResponseWriter, r *http.Request)

The ResizeImage function in the code above has the correct signature so it can be deployed. You’ll notice that it’s just a http.HandlerFunc from the Go standard library.

$ gcloud functions deploy ResizeImage --runtime go111 --trigger-http

availableMemoryMb: 256

entryPoint: ResizeImage

httpsTrigger:

url: Deploying function (may take a while - up to 2 minutes)...done.availableMemoryMb: 256entryPoint: ResizeImagehttpsTrigger:url: https://xxx.cloudfunctions.net/ResizeImage

Our function is deployed and we get the endpoint url in return. Big gopher images here we come !

Local development

To test this code as I was writing it, I’ve used a local development server to run the handler. During development, it would be pretty inconvenient to redeploy each time I make a small change to test and I also couldn’t find a local Golang cloud functions emulator (There is a node.js emulator, so hopefully a Go version is planned ?). However, the setup with a local server worked out pretty well for this simple function.

Next Steps

This a simple example but hopefully it can help you to get started with Golang on Cloud Functions. If we wanted to make this project production-ready here are some examples of the next steps we could take:

Add Unit tests

Cache the input images

Cache the output images

Add Authentication

Benchmark resizing libraries to find the fastest alternative

Thanks for reading and happy resizing !

Github Repo: https://github.com/didil/gcf-go-image-resizer