
Mock API for prototyping UIs: CSV into SQLite, filters, and OpenAPI contracts
Lab for a public mock API with ready-made datasets (products, postal codes, movies, and more) to prototype frontends without a real backend. The core is Hono on Bun with a SQLite cache fed by files under data/. It has SQL filters, search and sort, typed OpenAPI, fake mutations, and mock auth. Reimport runs only at boot when the manifest changes, with no runtime watch.
Technical context
I modeled Mockê as a modular monolith on Bun: each dataset (products, postal codes, news, movies, users, companies) is a module with paginated listing, get by id, HTML docs page, and OpenAPI tag. I chose Hono with typed routes and Zod because the HTTP contract needs to match the files in data/ (CSV and JSON) without a real domain backend. Files become TEXT tables in SQLite at boot; the API queries with SQL instead of keeping tens of thousands of rows in memory. Open CORS for GET, security headers, per-IP rate limit, and /health//ready close the path for Docker behind a proxy. Beyond reads, there are non-persistent fake mutations and a mock auth flow to exercise login on the frontend.
Engineering challenges (how and why)
- Atomic sync by manifest: at boot, I hash name|size|mtime of files under
data/and compare with_metain SQLite. If it changed, I import into a temporary file with a WAL checkpoint and rename; if the rebuild fails and a valid cache already existed, I keep the previous one. - Rich SQL listing: pagination, search, sort, and projection params are reserved; any other query param that exists on the dataset becomes equality, with commas as OR and match on multi-value cells. Unknown fields are ignored so exploratory clients do not break.
- Contracts validated at boot: Zod schemas in the catalog sample up to 100 rows and fail the process if the file lacks the promised fields or if the sample does not parse, avoiding serving inconsistent JSON.
- Mirrored modules, shared query: adding a resource is a file in
data/, Zod routes, HTML docs, and catalog registration; listing and get reuse the same SQL layer, without a generic factory for typed routes. - Per-IP rate limit: fixed in-memory window; the IP comes from the first hop of
X-Forwarded-Forwhen present, otherwise from the socket. There is no trusted-proxy flag: the header is accepted if it exists. - Readiness in the container: Docker uses multi-stage Bun, an optional
.cachevolume, and a HEALTHCHECK on/ready, which requires SQLite responding and every contract dataset present, with a start-period long enough for the first import.
- Bun
- Hono
- SQLite
- Zod
- OpenAPI
- Docker