Skip to content

ccherrad/FizzBuzz

Repository files navigation

FizzBuzz API

A FizzBuzz generator exposed over HTTP, with a built-in tracking system that records which parameter combinations are called most frequently.

What it does

  • GET /api/v1/fizzbuzz — generates a FizzBuzz sequence for any divisors, limit, and custom strings
  • GET /api/v1/stats/ — returns the most frequently requested parameter combination and its hit count
  • GET /health — health check

Architecture

The project is split into three modules:

  • fizzbuzz — pure stateless logic, no I/O
  • tracker — request tracking via SQLite, completely decoupled from fizzbuzz
  • api — FastAPI app wiring both modules together

Tracking is applied via a @track_request decorator on the router handler. This keeps the fizzbuzz logic clean and the tracking concern isolated — adding or removing tracking doesn't touch the business logic.

Endpoints

GET /api/v1/fizzbuzz

Param Type Constraint Description
int1 int > 0 First divisor
int2 int > 0 Second divisor
limit int > 0, ≤ 10000 Sequence length
str1 str required String for multiples of int1
str2 str required String for multiples of int2

Example:

GET /api/v1/fizzbuzz?int1=3&int2=5&limit=15&str1=Fizz&str2=Buzz
{
  "result": ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz"]
}

GET /api/v1/stats/

Returns the most frequently requested parameter combination.

{
  "hits": 42,
  "requests": [
    { "int1": 3, "int2": 5, "limit": 15, "str1": "Fizz", "str2": "Buzz" }
  ]
}

Returns {} if no requests have been made yet.

Design decisions

Decorator-based tracking@track_request inspects the function signature at call time and serializes params to JSON before persisting. The fizzbuzz router has no awareness of the tracking layer.

SQLite with WAL mode — lightweight, no infrastructure needed. WAL journal mode + synchronous=NORMAL gives a good balance between write performance and crash safety.

Validation at the router layer — FastAPI query constraints (gt=0, le=10000) reject invalid input before it reaches the service. The service stays pure.

Dev/prod distinctionENV=dev enables uvicorn hot-reload by passing the app as an import string. Production passes the app object directly.

Running locally

uv sync
uv run fizzbuzz

With hot-reload:

ENV=dev uv run fizzbuzz

Running with Docker Compose

docker compose up

Runs with ENV=dev (hot-reload enabled), persists the SQLite DB in ./data, and reflects code changes without rebuilding.

Running tests

uv sync --all-groups
uv run pytest

Each test runs against an isolated SQLite database per test — no shared state between tests.

CI

GitHub Actions runs on every push and pull request to main:

  • Lintruff check + ruff format --check
  • Testpytest

What would come next

  • Async SQLAlchemy (AsyncSession + aiosqlite) to avoid blocking the event loop on DB writes
  • Auth on the stats endpoint
  • Proper migrations (Alembic)
  • Rate limiting

About

FizzBuzz over HTTP with request tracking

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors