An interesting requirement came up at work this week where we discussed potentially having to run our own URL Shortener because the Universal Links mechanism (in iOS 9 and above) requires a JSON manifest at
Since the OS doesn’t follow redirects this manifest has to be hosted on the URL shortener’s root domain.
Owing to a limitation on AppsFlyer it’s currently not able to shorten links when you have Universal Links configured for your app. Whilst we can switch to another vendor it means more work for our (already stretched) client devs and we really like AppsFlyer‘s support for attributions.
Which brings us back to the question
“should we build a URL shortener?”
swiftly followed by
“how hard can it be to build a scalable URL shortener in 2017?”
Well, turns out it wasn’t hard at all as it took me less than 2 hours to have everything implemented, tested and deployed!
For this URL shortener we’ll need several things:
all of which can be accomplished with API Gateway + Lambda.
Overall, this is the project structure I ended up with:
Seeing as this is a static JSON blob, it makes sense to precompute the HTTP response and return it every time.
For an algorithm to shorten URLs, you can find a very simple and elegant solution on StackOverflow. All you need is an auto-incremented ID, like the ones you normally get with RDBMS.
However, I find DynamoDB a more appropriate DB choice here because:
but, DynamoDB has no such concept as an auto-incremented ID which the algorithm needs. Instead, you can use an atomic counter to simulate an auto-incremented ID (at the expense of an extra write-unit per request).
Once we have the mapping in a DynamoDB table, the redirect endpoint is a simple matter of fetching the original URL and returning it as part of the Location header.
Oh, and don’t forget to return the appropriate HTTP status code, in this case a 308 Permanent Redirect.
Finally, for the index page, we’ll need to return some HTML instead (and a different content-type to go with the HTML).
I decided to put the HTML file in a static folder, which is loaded and cached the first time the function is invoked.
Fortunately I have had plenty of practice getting Lambda functions to production readiness, and for this URL shortener we will need to:
If you put in the same URL multiple times you’ll get back different short-urls, one optimization (for storage and caching) would be to return the same short-url instead.
To accomplish this, you can:
I think it’s better to add a GSI than to create a new table here because it avoids having “transactions” that span across multiple tables.
Like what you’re reading but want more help? I’m happy to offer my services as an independent consultant and help you with your serverless project — architecture reviews, code reviews, building proof-of-concepts, or offer advice on leading practices and tools.
I’m based in London, UK and currently the only UK-based AWS Serverless Hero. I have nearly 10 years of experience with running production workloads in AWS at scale. I operate predominantly in the UK but I’m open to travelling for engagements that are longer than a week. To see how we might be able to work together, tell me more about the problems you are trying to solve here.
I can also run an in-house workshops to help you get production-ready with your serverless architecture. You can find out more about the two-day workshop here, which takes you from the basics of AWS Lambda all the way through to common operational patterns for log aggregation, distribution tracing and security best practices.
If you prefer to study at your own pace, then you can also find all the same content of the workshop as a video course I have produced for Manning. We will cover topics including:
You can also get 40% off the face price with the code ytcui. Hurry though, this discount is only available while we’re in Manning’s Early Access Program (MEAP).