In this article we’ll build a simple yet powerful short link service using two of my favorite Google Cloud technologies: Cloud Run and Firestore. The code can be found on Github and here’s a slide version of this story.
I love building demos but sometimes they can feel a bit artificial, like you’re building a program that no one would actually want to use, just to illustrate some capability or technique. But if you choose carefully, you can find demos that are both simple and useful, which for me is the best possible vehicle for learning.
What problem are we trying to solve?
I always like to start any work with a problem statement because, as Lewis Carroll said, “if you don’t know where you’re going, any road will get you there”. Here’s my problem statement:
I want to share my teaching artifacts but I hate long, hard to remember URLs. In the past I’ve used a short link service, like
bit.ly, but there are some problems with that approach:
- globally shared namespace - Good luck getting your hands on
bit.ly/cloud. Like the Internet Domain Name System, the gold rush is over and all the nice short names are gone.
- trust - Links you publicize can have a life of their own so you’re trusting this service to be a responsible, reliable, and secure custodian of your data.
- privacy - Allowing another party to manage your links means they have complete visibility over all of your traffic.
- branding - You turn over your branding to the company serving your links. Wouldn’t it be nice to have your own identity embedded in your short links?
What does it mean, to me, to solve this problem?
- I own the whole namespace so I get first crack at the shortest short links possible.
- The service should use my domain name and branding.
- I don’t want to spend much time maintaining this app so I’d like it to be simple and small (<500 lines of code, please).
- It must be scalable, so that it doesn’t crash under the intense weight of my wildly popular articles (ok, that’s never happened but I can dream, can’t I?).
- I’d like a clean landing page providing a directory of all available short links.
- I want some basic analytics so that I can see the relative popularity of each link.
- I want to use 100% managed services. I don’t want to directly think about, or even be aware of, any servers.
Thanks to my last requirement, this program is so simple it hardly warrants a design diagram but old habits die hard, so here’s mine:
Database - Cloud Firestore
I chose Cloud Firestore for my database because it’s SIMPLE (Scalable, Intuitive, Managed, Pay-as-you-go, Language-agnostic, and Economical).
My data model is also quite simple: one document field per short link, each containing a map of these values:
- key - a short link part of the URL (e.g. “foo” for
mco.fyi/foo), naming the map
- url - the long link, i.e. where to redirect requests for a given short link
- count - keeps track of how many times a given short link was accessed
- desc - a human friendly description of where a given short link takes you
- private - a boolean value which hides the short link from the public list
Here’s the data model in action as seen in the Google Cloud Console:
One thing I really like about Firestore is you can use the console to update your data as well as view it. It essentially gives me a database administration user interface for free. Less work for me!
Web Front End - Skeleton
I’m using a styling package called skeleton, which I quite like because it’s simple, small, and responsive. Here’s an abbreviated copy of the HTML for my home page:
Click here to expand code
I wanted my home page to simply list all the available short links, dynamically, and that’s exactly what the
div element starting at line 42 does. A bit later, we’ll visit my server code, which populates the data incorporated into this template.
Here’s an abbreviated copy of the HTML for my 404 page, which is needed for the case when a non-existent short link is requested. You can experience this page yourself by visiting mco.fyi/foo (you may need to have seen a certain film in order to appreciate the joke):
Click here to expand code
Server - Cloud Run
For my web server, I chose Cloud Run because, like Firestore, it’s SIMPLE (Scalable, Intuitive, Managed, Pay-as-you-go, Language-agnostic, and Economical). It doesn’t make me think about servers, or scaling, or any of the annoying system administration details I don’t want to deal with.
Of course, I want this service to live behind a nice short domain name so I snarfed up
mco.fyi (the “fyi” top level domain feels just right for this kind of service). Cloud Run makes it super easy to assign your own domain name to a service and you get secure serving via SSL/TLS/https automatically and painlessly.
I chose to write my server in Go, because it’s my favorite system programming language. Because Cloud Run is language and environment agnostic, I could have just as easily used Python, Java, Ruby, or FORTRAN for that matter (ok, FORTRAN might be a challenge but wouldn’t that be fun?).
Here’s my server code, which is small enough to fit into one main.go source file:
Click here to expand code
mainfunction (line 73) grabs a snapshot of the database on line 86.
- On line 98
mainarranges to dispatch the
redirectfunction on every incoming request on port 8080.
- The redirect function (line 24) is the real workhorse here. It looks for the requested short link and…
- if it sees no short link in the request URL, it serves up the home page on line 48.
- if it finds a known short link, it redirects the requesting browser on line 63.
- if it finds an unknown short link, it returns the 404 page on line 69.
- It also serves artifacts (image and css files) for the home page on line 53.
- The function defined on line 87 runs in the background indefinitely. It gets notified anytime the dataset changes, and reloads the local copy in response to those notifications so that the running instance always has the latest version of the data handy. That way whenever I update the list of short links, I don’t need to redeploy the Cloud Run app.
The basic building block for a Cloud Run app is a container so I needed to write a Dockerfile, which can be thought of as the container blueprint for this app. As containers go, this is a pretty simple one:
All together now
Now let’s tie everything together. Here’s my deployment script:
Here’s what the Cloud Run console looks like after deploying my service:
One thing I’m quite happy with is the size of this app:
Here’s the final version of my site in all it’s glory:
That cute guy you see on the home page is Meiko. Whenever you visit a short link at
mco.fyi/something, his job is to go fetch the long version and return it to your browser. Thanks to Meiko (and Google), my short link service is SIMPLE (Scalable, Intuitive, Managed, Pay-as-you-go, Language-agnostic, and Economical) and useful. If you’d like to try this code for yourself, it’s available on Github and here’s a slide version of this story.