Not Another URL Shortener

So not only have I put a blog live, I’ve also deployed a usable service: naus (pronounced n-ow-s). As you might have guessed from the post title it stands for

Not Another URL Shortener

With such an edgy and captivating name you might be thinking,

“Why create another URL / Link shortener?”

And dear reader, that is an excellent question. I did it because I wanted to get more comfortable with a few technologies I use in my day job and by releasing something small, I can more effectively iterate on it whilst potentially building a user base by it being free. That’s right, free 😱

What’s it built on?

The technologies I used were:

  1. NodeJS + TypeScript
  2. React
  3. NextJS
  4. DynamoDB
  5. Serverless
  6. AWS Lambda
  7. ExpressJS

I’ve had a lot of experience with JavaScript and NodeJS in the past and, as much as I like the loose typing, I lament having to make anything remotely complex or data driven with pure JavaScript and Node. Passing around objects without types makes it difficult for me to keep track of the data that I’m pushing through my systems. Adding TypeScript on top of NodeJS gives me the type safety I so dearly crave, whilst giving me all of the flexibility and great features of JavaScript. Other languages such as Golang did cross my mind but I primarily write TypeScript at work and also I wanted to use the serverless framework.

React & NextJS are used for the homepage of https://naus.dev. Not much to say here, except that the site is hosted entirely in an S3 bucket which is pretty neat.

DynamoDB is an interesting technology. I wanted to use it because it’s dirt cheap so I can host the worlds greatest free URL shortener for next to nothing.

For those unaware, DynamoDB is a NoSQL database offered by Amazon. DynamoDB schema design is an interesting topic, which I might do another post about. Very briefly, you must think about your data in a hierarchy, rather than in relations. Thinking about your data in relations leads you in to the most common pitfall of splitting your data across multiple tables and using a key to relate them. If you’re doing this, you’ve played yourself and you might as well just use a relational database.

Serverless is a framework for “quickly” deploying your application to the cloud, regardless of the provider. Because I’m using DynamoDB I’m vendor locked into AWS, but if I weren’t, I could have easily told Serverless to deploy to Google Cloud Platform at a single configuration change. It’s so easy that I won’t be using it again. Serverless provides it’s key benefit (in my opinion) in setting up, the absolute ball ache that is, API Gateway. However, my API is built with express so I only require a single API Gateway route which proxy’s the request to the lambda. As much as I detest API Gateway, I could do that manually because it’s never going to change. Serverless also uses CloudFormation behind the scenes and I had some issues with CloudFormation not running because the previous deploy buggered something. Next time, I’m just doing to use Gitlab CI to zip and upload my code to Lambda and I’ll setup API Gateway manually the one time before I deploy for the first time.

AWS Lambda is a fantastic technology. And, just like DynamoDB, the reason I chose it is because it’s dirt cheap. I pay per invocation, and seeing as I’m the only soul using https://naus.dev it costs me nothing. It also means I don’t have to manage any infrastructure such as containres or EC2 instances.

ExpressJS I have a lot of experience with and I like it. It handles all of the routing in the API and is pretty nippy. I originally made the API using middy and a more extensive serverless config. But I refactored it for 2 reasons:

  1. It locked me in to serverless pretty heavily
  2. Middy fucking sucks

Middy is absolute ass. Trying to setup middleware, in a TypeScript environment, was a complete ball ache. The compiler was crying at me more frequently than a new born baby because I couldn’t find the right type to use and when I did, I had to define technically optional properties on my middleware because they were not declared as optional in their type definitions. Being bogged down in serverless configuration will also end up in tears, trust me on that. Express is much more familiar and intuitive to me so I was able to work more quickly on the project.

Closing ramblings

So there it is. My first technical, but not actually that technical, write up of my first project I’m not scared to share with the world. I hope you enjoyed it. Thoughts and suggestions so you can always email me at mark@93labs.dev or send me angry tweet on Twitter.

Also if you need a link shortening, be sure to check out naus and let me know what you think.