Design
I got out of bed and turned on the lights in my office. I sat down on my ergonomic chair and power up a comically large curved monitor. Arch boots up. I quickly message a friend of mine on Signal to remind them that I use Arch. Now I’m ready to code. Let’s build this thing. The API is going to be simple. No reason for GUIs or anything like that - I am engineer, therefore I’ve convinced myself that UI’s peaked with the 1970’s teletype. Life’s short so I’m going to build an HTTP API. The simplest thing I can come up with. You can shorten URLs like this:Building the Barebones - 09:59 minutes remaining
I’m using Shuttle for this project. It’s a serverless platform built for Rust and I don’t have to deal with provisioning databases, or subdomains or any of that gunk. I already have the CLI installed. I stop and think for a little bit - which web framework do I want to use? I think I’m going to go with Rocket. It’s pretty much production ready with a sweet API and I’m reasonably proficient with it. To initialize a rocket project with boilerplate, I can use the Shuttle CLIinit
command:
main.rs
file:
main.rs
init
command takes care
of this as well, leaving us with the following Cargo.toml
:
Cargo.toml
init
command also created a new Shuttle project for us. This starts an
isolated container in Shuttle’s infrastructure.
Now, to deploy:
Adding Postgres - 07:03 minutes remaining
This is the part of my journey where I usually get a little flustered. I’ve set up databases before, but it’s always a pain. You need to provision a VM, make sure storage isn’t ephemeral, install and spin up the database, create an account with the correct privileges and secure password, store the password in some sort of secrets manager in CI, add your IP address and your VM’s IP address to the list of acceptable hosts etc etc etc. Oof that sounds like a lot of work. Shuttle does a lot of this stuff for you - I just didn’t remember how. I quickly head over to the Shuttle shared database section in the docs. I added thesqlx
dependency to Cargo.toml
and change
one line in main.rs
:
rocket
function, Shuttle
will
automatically provision a Postgres database for you, create an account and hand
you back an authenticated connection pool which is usable from your application
code.
Lets deploy it and see what happens:
Setting up the Schema - 06:30 minutes remaining
The database provisioned byShuttle
is completely empty - I’m going to need to
either connect to Postgres and create the schema myself, or write some sort of
code to automatically perform the migration. As I start to ponder this seemingly
existential question I decide not to overthink it. I’m just going to go with
whatever is easiest.
I connect to the database provisioned by Shuttle using
pgAdmin using the provided database URI and run the
following script:
id
used for the url lookup is a primary key, which is implicitly a
‘unique’ constraint, Postgres would create the index for me. Cool.
Writing the Endpoints - 05:17 remaining
The app’s going to need two endpoints - one toshorten
URLs and one to
retrieve URLs and redirect
the user.
I quickly created two stubs for the endpoints while I thought about the actual
implementation:
INSERT
statement. Hm - what about duplicates? I decided
not to overthink it 🤷.
redirect
method in a similar spirit. At this point I
started to panic as it was really getting close to the 10 minute mark. I’ll do a
SELECT *
and pull the first url that matches with the query id. If the id does
not exist, you get back a 404
:
Moment of truth - 00:25 minutes remaining
Feeling like an off-brand Tom Cruise in mission impossible I stared intently at the clock counting down as Shuttle deployed my url-shortener. 19.3 seconds and we’re live. As soon as theDEPLOYED
dialog came up, I instantly tested it out: