Skip to content

faizan2786/link

Repository files navigation

Link: URL Shortener

A concurrent, in-memory URL shortener service written in Go. This is a practical project demonstrating Go's concurrency primitives (sync.RWMutex, sync/atomic), REST API design, middleware composition, and client-server architecture.

Architecture

The project consists of:

  • linkd (Daemon/Server): The REST API backend that handles shortening URLs, resolving short keys to original URLs, and atomically tracking click metrics.
  • linkc (Client): A command-line client to interact with the shortener service.

Architecture Diagram

Internal Packages

  • internal/httpio: HTTP I/O utilities. Defines a chainable Handler type (a func(w, r) Handler where each handler returns its next step), a Responder with pre-built handlers for JSON, text, redirect, and error responses, a JsonDecoder that reads, unmarshals, and optionally validates request bodies via a Validate() error interface, and a MaxBytesReader that unwraps wrapped ResponseWriters before applying a size limit.
  • internal/hlog: Request logging middleware. Captures response StatusCode and Duration via composable MiddlewareFunc wrappers and logs each request with structured attributes using log/slog.
  • internal/traceid: Distributed tracing utilities. Generates UUID-based trace IDs, propagates them through context.Context, and enriches every slog log record with the trace ID via a custom slog.Handler.

Features & Details

  • Concurrency: Utilizes sync.RWMutex for safe concurrent access to the in-memory store and sync/atomic for race-free click tracking.
  • Chainable Handlers: The httpio.Handler type enables a clean handler-chaining pattern — each handler returns its next step, and ServeHTTP drives the chain. This avoids third-party router dependencies while keeping handler logic composable.
  • JSON & Form Support: The /shorten endpoint accepts both application/json and application/x-www-form-urlencoded request bodies, with a 4 KB request size limit to guard against oversized payloads.
  • REST Endpoints:
    • GET /: Health check.
    • POST /shorten: Shorten a URL (accepts JSON or form data; returns {"key": "<key>"} on success).
    • GET /resolve/{key}: Resolve a shortened key to its original URL (HTTP 302 redirect) and increment its click counter.
    • PUT /update/{key}: Update the destination URL for an existing key.
  • Observability: Every request is logged with method, URL, status code, and duration. A UUID trace ID is injected into each request's context and automatically attached to all related log records via a custom slog.Handler.

Usage

Running the Server

Start the daemon with optional flags:

go run ./cmd/linkd/main.go
go run ./cmd/linkd/main.go -addr localhost:9090 -timeout.read 2s -timeout.idle 10s
Flag Default Description
-addr localhost:8080 Address to listen on
-timeout.read 1s HTTP server read timeout
-timeout.idle 5s Idle connection timeout

Running the Client

Use the client to interact with the API:

go run ./cmd/linkc/main.go

The linkc CLI supports the following commands:

  • health: Check the server status.
  • shorten <link> [key]: Shorten a given link with an optional custom key.
  • resolve <key>: Resolve a shortened key back to its original link.
  • update <key> <link>: Update the destination link for an existing key.

Testing

To run the tests, data race tests, and benchmarks for this specific project:

go test ./...
go test -race ./...
go test -run=' ' -bench=. ./...

About

A URL Shortener HTTP Server (and Client)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages