$ show typicode/json-server
JSON Server v1 (beta) is a CLI tool and library that spins up a fully functional REST API from a JSON or JSON5 file. It is built on top of lowdb for data persistence and @tinyhttp/app for HTTP handling. The architecture is a clean three-layer design: a CLI entry point (bin.ts) that wires file watching and server startup, an Express-like app layer (app.ts) that defines routes and parses query parameters, and a service layer (service.ts) that encapsulates all data access, filtering, pagination, and relationship embedding. The system supports advanced query capabilities including field operators (gt, lt, in, contains, etc.), JSON-based _where queries, sorting, pagination with navigation metadata, and resource embedding via _embed. It also handles referential integrity on deletes by nullifying foreign keys or cascading dependent deletions. The codebase demonstrates solid TypeScript craftsmanship with strict mode enabled, modern ESM modules, and a clear separation of concerns. Notable engineering patterns include the NormalizedAdapter wrapper that enforces string IDs and strips $schema on read while re-injecting it on write, and the Observer adapter that intercepts lowdb read/write lifecycle events to enable file-watch reloading without feedback loops. The query parsing layer cleanly separates URLSearchParams-based operator syntax from raw JSON _where objects, with proper type coercion for booleans, null, and numbers. The project is in active beta (v1.0.0-beta.15) with recent commits, CI via GitHub Actions, and a pre-commit hook running tests. It targets Node.js >=22.12 and leverages experimental TypeScript stripping for development. Dependencies are current and well-chosen (lowdb v7, @tinyhttp v3, eta v4). The test suite uses Node's built-in test runner and covers the service layer, query parsing, pagination, and full HTTP integration tests.
The LLM identified 5 files worth highlighting for reuse:
Parses URL query strings into structured JSON filter objects supporting both colon-style (views:gt=100) and legacy underscore-style (views_gt=100) operators. Handles nested dot-paths via dot-prop, coerces string values to number/boolean/null, and parses comma-separated 'in' arrays. Self-contained and reusable for any project needing query-string-to-filter-object conversion.
Evaluates whether an arbitrary object matches a structured where-clause with support for comparison operators (eq, ne, lt, lte, gt, gte), set membership (in), string operations (contains, startsWith, endsWith - all case-insensitive), nested object traversal, and 'or' composition. Pure function with no external dependencies beyond type definitions - easily extractable as a standalone in-memory query engine.
Generates paginated results with full navigation metadata (first, prev, next, last, pages, items). Handles edge cases robustly: clamps out-of-range pages, normalizes invalid perPage to 1, and produces stable empty pagination for empty arrays. Pure function, fully generic over <T>, zero dependencies - directly reusable.
Wraps any lowdb Adapter to enforce data invariants on read/write: strips $schema on read, converts numeric IDs to strings, auto-generates missing IDs using randomId, and re-injects a default $schema on write. Demonstrates the decorator/adapter pattern for transparent data normalization - applicable to any storage layer needing schema enforcement.
Wraps a lowdb Adapter and exposes lifecycle hooks (onReadStart, onReadEnd, onWriteStart, onWriteEnd) that fire around every read/write operation. Used by the CLI to detect external file changes vs. self-initiated writes, preventing reload loops. A clean reusable pattern for adding observability to any async storage adapter.