Requirements


Functional Requirements:


  • Create a short URL for a given long URL.
  • Return the long URL associated with a given short URL.
  • (Optional) Support custom domain.
  • (Optional) Auth if we want to have the user manage their shortened URLs.



Non-Functional Requirements:


  • Low latency: the user needs to get to the target page quickly.
  • High throughput: we don't want to limit the throughput of the downstream service.
  • Reliability: the URL shortener may be a key component in user's critical infrastructure.
  • Data retention: URLs not used for a long time should be freed up for re-use.
  • Security: we don't control how the URL creator uses it further. It is not our task to handle the access to the shortened URL.
  • Idempotency: creating a shortened URL for the existing long URL should return the same entry.


API Design

Two interaction paths:

  • Write: user creates a shortened URL
  • Read: user navigates/calls the shortened URL and gets redirected to the full URL.


Write POST /create

Accepts JSON body containing "originUrl" property. We won't use query parameters as the original URL may exceed the query param limit.


Returns a JSON containing "shortUrl" property with the shortened URL.


Read GET /<short_url_id>

Returns a 308 response (permanent redirect) and Location header pointing to the full URL.


High-Level Design

Main components:

  • Stateless service handling REST requests.
  • DB maintaining the mapping between long and short URLs.



Detailed Component Design

Server:

Simple application (e.g., Spring Boot server app or a NodeJS express server). Using an async framework (e.g., Reactor) may be beneficial as the application is IO-bound.


POST /create

  1. Extract and sanitize the input (should be a valid URL).
  2. Hash it into the available space (e.g., fixed-length alphabetical string). Let's assume a string of English letters with a length of 12. Would support 26^12 short URLs. With custom domain logic, we can scope IDs per domain, but that's a follow-up.
  3. Insert the mapping of short ID to a long URL into the DB.
  4. Return 200 and a new URL if insert succeeded.
  5. Return 201 and the existing URL if the entry already exists.


GET /

  1. Extract and sanitize teh input (should be a valid URL ID).
  2. Look up the full URL in the DB.
  3. Return 308 with the full URL in the Location header.
  4. Return 404 if the mapping is not present.