Requirements


Functional Requirements:


  • Verified Fact: The problem requires two core operations: create a short URL and resolve a short URL.
  • Verified Fact: The core data model is a mapping from a unique short code to a long URL plus metadata.
  • Verified Fact: The redirect path is latency-sensitive because it sits directly in front of end users.
  • High-Probability Inference: Reads will usually be much higher than writes.
  • High-Probability Inference: Traffic will be skewed. A small set of links will become hot.
  • High-Probability Inference: Analytics are valuable, but they should be asynchronous, not in the redirect hot path.
  • Unknown: QPS, storage horizon, number of regions, whether links can expire, whether aliases are mutable, whether custom aliases are required, whether identical long URLs should deduplicate, and how aggressive anti-abuse rules must be.

I am not inventing traffic numbers. Without them, the honest design is a solid baseline that scales in the standard read-heavy case.



Non-Functional Requirements:


  1. Low latency. Redirects should usually complete with one cache lookup, or one key lookup on a primary store on cache miss.
  2. High availability. Redirects matter more than creation. If analytics fails, redirects must still work.
  3. Scalability. The read path must scale horizontally. The write path must scale enough to avoid a central bottleneck.
  4. Durability. URL mappings cannot disappear after a node failure.
  5. Consistency. After a successful create response, the short URL should be resolvable immediately or near-immediately.
  6. Reliability. Cache failure should degrade to the database, not take the service down.
  7. Security and abuse resistance. Validate URLs, rate-limit creation, block dangerous schemes, and support takedowns.
  8. Observability. Track redirect latency, cache hit rate, create failures, error rates, and abuse signals.

Priority order for a normal public shortener: redirect latency, redirect availability, mapping durability, horizontal scale, abuse handling, analytics.



API Design

Use a clean split between creation, redirect, and metadata lookup.

POST /v1/urls

{"long_url": "https://example.com/some/very/long/path","custom_alias": "spring-sale","expires_at": "2026-12-31T23:59:59Z"}

Success response:

{"short_code": "b9K2xQ","short_url": "https://sho.rt/b9K2xQ","long_url": "https://example.com/some/very/long/path","expires_at": "2026-12-31T23:59:59Z"}

Errors:

  • 400 invalid URL
  • 409 custom alias already taken
  • 429 rate limited

GET /{short_code}

Behavior:

  • If found and active: return 302 Found with Location: <long_url>
  • If not found: 404
  • If expired or disabled: 410 or 404, depending on product policy

GET /v1/urls/{short_code}

Purpose:

  • Returns metadata without redirecting
  • This directly satisfies the requirement to return the long URL for a short URL

Example response:

{"short_code": "b9K2xQ","long_url": "https://example.com/some/very/long/path","status": "active","created_at": "2026-04-02T10:00:00Z","expires_at": null}

One direct design point: I would not assume that the same long URL must always return the same short URL. That is a product decision, not a system-design fact.




High-Level Design