Backend & APIs · Beginner

Shrtn: URL Shortener API

Build a REST API that turns long links into short codes, redirects on lookup, and counts clicks, with rate limiting and tests.

Beginner8-14 hoursTypeScript

You will build a production-shaped URL shortener as a REST API: clients POST a long URL and receive a short code, then any GET request to that code is redirected to the original destination while a click counter increments in PostgreSQL. The project covers the full backend request lifecycle from routing and validation through database persistence and HTTP redirects. It is a compact but realistic scope that lets you practice REST design, relational data modeling, and test-driven development without getting lost in incidental complexity.

What you build

  • POST /links accepts a long URL and returns a unique short code
  • GET /:code performs a 302 redirect to the original URL and increments the click count
  • GET /links/:code/stats returns the original URL, creation date, and total click count
  • DELETE /links/:code removes a short link from the database
  • Per-IP rate limiting rejects clients that exceed a configurable request threshold
  • Input validation rejects malformed or non-HTTP URLs with a clear error response
  • Vitest integration tests cover the happy path and key error cases for each endpoint

What it teaches

  • Designing and implementing a REST API with clear resource naming and correct HTTP status codes
  • Relational schema design and running schema migrations with an ORM
  • Writing integration tests that hit real HTTP endpoints against a test database
  • Implementing middleware for cross-cutting concerns such as rate limiting and input validation
  • Generating short unique identifiers and handling collision detection in a database
  • Reading and writing environment configuration safely using dotenv or Node's built-in env handling

How it works

  1. 1

    Client

    • POST /links {url}
    • GET /:code
  2. 2

    Hono Router

    • Rate limit middleware
    • Validate input

    Returns 429 or 422 on failure

  3. 3

    Handler

    • Generate code (POST)
    • Lookup code (GET)
  4. 4

    PostgreSQL via Drizzle

    • INSERT link row
    • SELECT + UPDATE clicks
  5. 5

    Response

    • 201 + short code
    • 302 redirect to original URL
fig. 01 — request lifecycle for the two core operations

Sign in to open the build guide

Free account. Get the step-by-step build and every resource link.

Sign in to continue

Take it further

  • Add a custom alias option to POST /links so callers can request a vanity code like `shrtn.me/my-brand`.
  • Implement link expiry: accept an optional `expires_at` timestamp at creation and return 410 Gone after that date.
  • Add a minimal HTML dashboard served at GET / that lists recent links and their click counts using Hono's JSX support.

More like this

All projects