A platform where students learn backend engineering by writing real HTTP API handlers — not toy programs, not DSA puzzles. Write an Axum server, submit it, get it compiled and tested against a live PostgreSQL database.
Students pick a ticket, read a spec, implement a working Axum HTTP server, and submit. The server spins up their code, fires real HTTP requests at it, and checks the responses. Same loop real engineers do every day.
Supports multiple languages in future. Currently: Rust (Axum).
BROWSER SERVER (port 3000) POSTGRES
─────── ────────────────── ────────
┌──────────────────────┐
│ Frontend │ POST /register
│ React + Vite │ POST /login ┌────────────┐
│ Monaco editor │ ─────────────────────────────────▶ │ accounts │
│ │ ◀─────────────── { token } │ table │
│ ┌────────────────┐ │ └────────────┘
│ │ Problem list │ │
│ │ Code editor │ │ POST /submit ┌────────────┐
│ │ Results panel │ │ Authorization: Bearer <token> │ users │
│ │ Database tab │ │ ─────────────────────────────────▶ │ table │
│ └────────────────┘ │ └────────────┘
│ │ │
│ │ ┌────────────▼─────────────┐
│ │ │ runner::grade() │
│ │ │ │
│ │ │ 1. TRUNCATE + seed DB │
│ │ │ 2. write src to │
│ │ │ /tmp/api-trainer- │
│ │ │ cache/{problem_id}/ │
│ │ │ 3. cargo build (debug, │
│ │ │ incremental) │
│ │ │ 4. spawn binary │
│ │ │ PORT=free │
│ │ │ DATABASE_URL=... │
│ │ │ 5. wait for /health │
│ │ │ 6. fire test HTTP reqs │
│ │ │ 7. compare JSON structs │
│ │ │ 8. kill process │
│ │ └────────────┬─────────────┘
│ │ │
│ │ ◀── GradeResult ─┘
│ │ { passed, tests_passed,
│ │ tests_total, test_details,
│ │ compile_error?, runtime_error? }
│ │
│ │ GET /db/users ┌────────────┐
│ Database tab ───────│ ─────────────────────────────────▶ │ │
│ (live editor) │ POST /db/users │ live DB │
│ │ PUT /db/users/:id │ (same PG) │
│ │ DELETE /db/users/:id │ │
└──────────────────────┘ ◀───────────────────────────────── └────────────┘
server/ Rust backend — auth, problem listing, grading, DB API
shared/ Shared types (GradeResult, Submission, TestCaseResult)
frontend/ React + Vite + Monaco editor
| ID | Title | Tags |
|---|---|---|
| p001 | List Users | GET, SELECT |
| p002 | Get User by ID | GET, Path Params, 404 |
| p003 | Create User | POST, Insert, 201 |
| p004 | User Stats | GET, Aggregate, COUNT |
| p005 | Update User | PUT, Update, 404 |
No Rust, PostgreSQL, or Node.js required — everything runs inside containers.
# Docker
docker compose up --build
# Podman
podman compose up --buildOpen http://localhost:5173 once you see:
server-1 | INFO server: server listening on 0.0.0.0:3000
First build takes a few minutes (compiling Rust). Subsequent starts are fast — build cache is persisted in a volume.
Prerequisites: Rust (stable 1.88+), PostgreSQL, Node.js 18+
# 1. Create the database
createdb api_trainer
export DATABASE_URL=postgres://postgres:postgres@localhost:5432/api_trainer
# 2. Start the server (auto-runs migrations on startup)
cargo run -p server
# 3. Start the frontend (in a separate terminal)
cd frontend && npm install && npm run dev
# Open http://localhost:5173- Student registers/logs in → gets an auth token
- Submits source code + problem ID via web UI
- Server resets DB to known state (seeds fixtures for that problem)
- Server writes code into a persistent cargo project under
/tmp/api-trainer-cache/{problem_id}/ - Compiles with
cargo build(debug, incremental — first run ~30-60s, subsequent ~2-3s) - Spawns the student's server with
DATABASE_URL+ a freePORT - Fires HTTP requests matching the problem's test cases
- Compares JSON responses structurally (key order doesn't matter)
- Returns pass/fail per test case
- Add a
Problemstruct toserver/src/problems.rswith test cases and seed data - Add the problem definition to
frontend/src/App.tsx(PROBLEMS array) - Write a reference solution in
SOLUTIONS.md
See SOLUTIONS.md for reference implementations of each problem.
