HARTWELL_LABS

LinkShort

LinkShort (repository: `FastAPI-url`) is a complete URL-shortening service with a Python/FastAPI API, JWT-based authentication, per-user link

LinkShort

πŸ§ͺ View animated test results β€” 15/15 β†’

A production-ready URL shortener β€” FastAPI backend, JWT auth, click tracking, React 19 SPA, SQLite.

LinkShort (repository: FastAPI-url) is a complete URL-shortening service with a Python/FastAPI API, JWT-based authentication, per-user link management, click statistics, and a served single-page application frontend.

Stack: FastAPI (Python) Β· SQLAlchemy Β· SQLite Β· JWT (python-jose) Β· React 19 SPA (static files served by FastAPI) Β· pytest

Highlights

  • Full auth flow β€” register β†’ login β†’ JWT bearer tokens; /auth/me returns the current user
  • 6-character short codes β€” cryptographically random (secrets), with collision retry
  • Click tracking β€” every redirect increments the click counter
  • Link expiration β€” optional expires_in_seconds per link; expired links answer 410 Gone while stats stay viewable
  • Per-user URLs β€” /urls/my lists your links; deletes are owner-scoped
  • 302 redirects β€” /urls/r/{code} redirects to the target with a click recorded
  • Public stats β€” /urls/{code}/stats returns target + click count
  • SPA serving β€” FastAPI mounts the built React app and falls back to index.html for client-side routing
  • CORS open β€” allow_origins=["*"] for development

Tech stack

LayerTechnology
APIFastAPI (app = FastAPI(title="URL Shortener", version="1.0.0"))
ORMSQLAlchemy (Base.metadata.create_all on startup)
DatabaseSQLite
AuthJWT bearer tokens (python-jose)
Password hashingapp/auth.py (hashed, never stored plaintext)
FrontendReact 19 SPA in backend/static/
Testspytest (tests/test_api.py)

API surface

MethodPathAuthDescription
POST/auth/registerβ€”Create account, receive JWT
POST/auth/loginβ€”Authenticate, receive JWT
GET/auth/meBearerCurrent user profile
POST/urls/shortenBearerShorten a URL
GET/urls/myBearerList your URLs (newest first)
GET/urls/{code}/statsβ€”Public click stats
DELETE/urls/{code}BearerDelete your URL (owner-scoped)
GET/urls/r/{code}β€”302 redirect + click count
GET/healthβ€”Liveness probe

Repository layout

FastAPI-url/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ main.py            # FastAPI app, CORS, SPA serving
β”‚   β”œβ”€β”€ auth.py            # JWT creation/verification, password hashing
β”‚   β”œβ”€β”€ database.py        # SQLAlchemy engine + session
β”‚   β”œβ”€β”€ models.py          # User, URL models
β”‚   β”œβ”€β”€ schemas.py         # Pydantic schemas (UserCreate, Token, URLOut, URLStats)
β”‚   β”œβ”€β”€ config.py          # Settings
β”‚   └── routers/
β”‚       β”œβ”€β”€ auth_router.py # /auth/* endpoints
β”‚       └── urls.py        # /urls/* endpoints
β”œβ”€β”€ backend/static/        # Built React SPA (served by FastAPI)
β”œβ”€β”€ tests/
β”‚   └── test_api.py        # API integration tests
└── ...

Short-code generation

def gen_short() -> str:
    chars = string.ascii_letters + string.digits
    return ''.join(secrets.choice(chars) for _ in range(6))

6 characters from a 62-char alphabet β‰ˆ 5.7Γ—10¹⁰ combinations; collisions are checked and retried against the database.

On this page