ProjectsURL Shortener
A small web service, like bit.ly, that turns a long URL into a short code, redirects anyone who opens the short link, and lets a link be deleted. It's an introduction to designing an HTTP API: choosing methods and status codes, generating short keys that don't clash, keeping data safe across restarts, and making requests safe to repeat.
From Coding Challenges #12 ↗ by John Crickett
No sign-up. You tell the mentor your language: Java, Python or Node.js.
What you'll learn · 9 concepts
In the order the steps use them. Each one links to the best places to learn it, and you explain it in your own words once its steps are built.
Creating, following and deleting a short link use three different methods, and each outcome needs the right status code.
Covers: methods · status code classes · headers and bodies
An overview of HTTP (MDN) ↗ · HTTP response status codes (MDN) ↗ · RFC 9110: HTTP Semantics ↗
Step 1 defines the response fields and asks for a clear 400 error when the URL field is missing.
Covers: request and response shape · validating input at the edge · error responses that say what's wrong
RFC 9457: Problem Details for HTTP APIs ↗ · Zalando RESTful API Guidelines ↗
Step 1 asks how to generate a key for each URL, warns about short hashes colliding, and its bonus asks you to handle a duplicate key from a different URL.
Covers: hash functions · base-62 encoding · collisions and the birthday problem
Hash function (Wikipedia) ↗ · Birthday problem (Wikipedia) ↗
Step 2 turns a request for a short key into a redirect, and step 3's delete only works if clients keep coming back.
Covers: the Location header · permanent versus temporary codes · caching of redirects
Redirections in HTTP (MDN) ↗ · RFC 9110, section 15.4: Redirection 3xx ↗
Step 1 asks for creation to be idempotent, and step 3 asks for deleting a missing link to do nothing.
Idempotent (MDN Glossary) ↗ · Designing robust and predictable APIs with idempotency (Stripe) ↗
Step 1 asks where the links are stored, and step 3 requires that deleted links are gone from storage.
Covers: choosing a store · indexes for each lookup · uniqueness and check-then-insert races
PostgreSQL documentation: Constraints ↗ · Time-of-check to time-of-use (Wikipedia) ↗
Step 1 takes a URL from any client and later sends visitors to it, so what you accept decides what your service can be used for.
Covers: the parts of a URL · which schemes to accept · open redirects and phishing
What is a URL? (MDN) ↗ · URL Standard (WHATWG) ↗ · OWASP Unvalidated Redirects and Forwards Cheat Sheet ↗
The optional web form calls your API from a browser, possibly from a different origin.
Covers: the same-origin policy · CORS headers and preflight requests
Cross-Origin Resource Sharing (MDN) ↗ · Same-origin policy (MDN) ↗
The second optional step asks for every change to be built, tested and deployed automatically.
Continuous Integration (Martin Fowler) ↗ · GitHub Actions documentation ↗
What you'll build · 4 steps
Steps of 30 to 60 minutes, in your own editor and language. Each one has a check, so you know when it works.
Create the project for a small web service that you can run locally.
Works whenThe service starts and answers a request.
Accept a POST with a long URL in a JSON body, generate a short key, store the pair, and return the key, the long URL and the short URL. Submitting the same URL again returns the existing link. A malformed request gets a clear error. Bonus: handle two different URLs that produce the same key.
Works whenSubmitting a URL returns a success code and the three fields. Submitting it again returns the same key. A body without the URL field returns 400 with a message naming the missing field.
Concepts: HTTP · the API contract · short keys · idempotency · persistence and races in storage · URLs
A request for a short key redirects to its long URL. An unknown key gets a not-found answer.
Works whenA known key returns 302 with a Location header pointing at the long URL, and following it reaches the page. An unknown key returns 404 with a short message.
Concepts: redirects · HTTP
A DELETE for a short key removes it if it exists and does nothing if it doesn't.
Works whenAfter a delete, the key returns 404 and the pair is gone from storage. Deleting it again still succeeds.
Concepts: idempotency · persistence and races in storage
A page where a user pastes a long URL, submits it to your API and sees the short link, ideally with a button to copy it.
Works whenShortening a URL from the page shows the short link, and opening it redirects.
Concepts: cross-origin requests from a browser · the API contract
Every change to the code is built, tested and, if the tests pass, deployed automatically.
Works whenA pushed change runs the tests, and when they pass the deployed service has the change.
Concepts: automated build, test and deploy