miniurl.
// a small URL shortener API, written in Go

A URL shortener, kept small.

miniurl is a Go service backed by PostgreSQL and Redis. It exposes five HTTP endpoints — shorten a URL, shorten a batch, redirect, look up metadata, and a health probe. Clean architecture in the source, Docker Compose for local dev, and the UI you're looking at is served by the same binary.

Go + Fiber on the API Postgres + Redis for storage Snowflake + Base62 for codes 100k URLs per bulk call

01 — What's in the repo

The source follows a clean-architecture layout. Business rules sit in internal/domain and internal/usecase, which depend on nothing but each other. The Postgres and Redis adapters live under internal/repository, the HTTP handlers under internal/delivery/http, and main.go wires it all together at the composition root.

On the data side: a single urls table in Postgres holds every mapping, indexed by short_code. Redis fronts the hot lookups and also backs the per-API-key rate limiter. Short codes come from a Snowflake ID generator, Base62-encoded, so they stay collision-free without a lookup.

Bulk inserts go through pgx.CopyFrom rather than per-row INSERTs, which is why a single bulk call can take up to 100,000 URLs. API keys are checked by a header middleware, rate limits are enforced per-minute per-key, and the redirect path falls through Redis to Postgres and warms the cache on the way back.

02 — The API

Five endpoints. JSON in and out. Errors come back as { "error": "..." } with a matching HTTP status — 400 for bad input, 401 without a key, 404 on unknown codes, 409 on a custom-code collision, 410 if the link has expired.

Anything under /api/* requires X-API-Key. The dev key for local runs is dev-key; set API_KEYS in .env to change it.

01

Health probe

GET/health

No auth, no body. Useful for uptime monitors and Docker healthchecks.

request
curl https://mini-url.me/health
response
{ "status": "ok" }
02

Shorten one URL

POST/api/shorten

Takes a long URL, optionally a custom code (6–12 chars) and an expiry in days. Returns the short code, the full short URL, and the timestamps.

request
curl -X POST https://mini-url.me/api/shorten \
  -H "X-API-Key: dev-key" \
  -H "Content-Type: application/json" \
  -d '{
    "long_url": "https://example.com/very/long/path",
    "custom_code": "launch24",
    "expires_in_days": 30
  }'
response
{
  "short_code": "launch24",
  "short_url":  "https://mini-url.me/launch24",
  "long_url":   "https://example.com/very/long/path",
  "created_at": "2026-06-20T10:00:00Z",
  "expires_at": "2026-07-20T10:00:00Z"
}
03

Shorten in bulk

POST/api/bulk/shorten

Accepts up to 100,000 URLs in a single request. Inserts via Postgres COPY for throughput. Optional custom_codes array (matching length) and shared expiry.

request
curl -X POST https://mini-url.me/api/bulk/shorten \
  -H "X-API-Key: dev-key" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://example.com/a",
      "https://example.com/b"
    ],
    "expires_in_days": 7
  }'
response
{
  "total": 2,
  "results": [
    { "short_code": "aB3xZ", "short_url": "https://mini-url.me/aB3xZ" },
    { "short_code": "kP9mQ", "short_url": "https://mini-url.me/kP9mQ" }
  ]
}
04

Redirect

GET/:short_code

Resolves the short code (Redis first, Postgres fallback, cache warm-back) and returns a 301 to the long URL. Bumps a Redis click counter asynchronously.

request
curl -i https://mini-url.me/launch24
response
HTTP/1.1 301 Moved Permanently
Location: https://example.com/very/long/path
05

Lookup metadata

GET/api/urls/:short_code

Fetches the stored record for a short code without redirecting. Used for internal tools or to confirm what a code points to.

request
curl https://mini-url.me/api/urls/launch24 \
  -H "X-API-Key: dev-key"
response
{
  "id": 1024,
  "short_code":  "launch24",
  "long_url":    "https://example.com/very/long/path",
  "created_at":  "2026-06-20T10:00:00Z",
  "expires_at":  "2026-07-20T10:00:00Z",
  "click_count": 0
}

03 — Run it locally

The repo ships with a docker-compose.yml that brings up Postgres, Redis, and the API together. You don't need Go installed to try it.

bring it up
git clone <repo>
cd short-url/api
docker compose up -d --build
health check
curl http://localhost:8080/health
# { "status": "ok" }
shorten something
curl -X POST http://localhost:8080/api/shorten \
  -H "X-API-Key: dev-key" \
  -H "Content-Type: application/json" \
  -d '{"long_url":"https://example.com"}'
follow the redirect
# replace <code> with the short_code from the previous response
curl -iL http://localhost:8080/<code>
tear it down
docker compose down       # stop containers
docker compose down -v    # also wipe the Postgres volume

Without Docker: run postgres and redis locally, copy .env.example to .env, and go run . — the schema migrates on first boot.