mockhttpkit
mockhttpkit
Turn your Zod schemas into a working mock REST API, with CRUD routes, realistic fake data and request validation, in one command.
npm install --save-dev mockhttpkit zod
npx mockhttpkit start --schema ./schema.ts
The npm package is mockhttpkit; the command it installs is mockhttpkit. Requires Node.js 18.17 or newer.
Quick start
1. Install into your project (or an empty folder):
npm install --save-dev mockhttpkit zod
2. Write a schema file. Every exported z.object() becomes a REST resource.
// schema.ts
import { z } from 'zod';
export const UserSchema = z.object({
id: z.number().int(),
name: z.string(),
email: z.string().email(),
role: z.enum(['admin', 'member']),
});
export const PostSchema = z.object({
id: z.number().int(),
userId: z.number().int(),
title: z.string(),
published: z.boolean(),
});
3. Start the server:
npx mockhttpkit start --schema ./schema.ts
mockhttpkit running at http://localhost:4000
/posts 10 items (PostSchema)
/users 10 items (UserSchema)
12 routes · GET http://localhost:4000/ for the full list · Ctrl+C to stop
4. Call it. Paste these into a second terminal. On Windows, use Git Bash or curl.exe; in Windows PowerShell 5, plain curl is an alias for a different command.
Fetch one record (the fake values will differ each run):
curl http://localhost:4000/users/1
{"id":1,"name":"Ms. Joyce Dooley MD","email":"marcelle_corwin-stanton@gmail.com","role":"admin"}
Filter and limit a list:
curl "http://localhost:4000/users?role=admin&_limit=2"
[{"id":1,"name":"Ms. Joyce Dooley MD","email":"marcelle_corwin-stanton@gmail.com","role":"admin"},{"id":2,"name":"Lowell Heller Sr.","email":"mercedes12@yahoo.com","role":"admin"}]
Create a record. It's validated against UserSchema and gets the next id:
curl -X POST http://localhost:4000/users \
-H "Content-Type: application/json" \
-d '{"name":"Ada Lovelace","email":"ada@example.com","role":"admin"}'
{"id":11,"name":"Ada Lovelace","email":"ada@example.com","role":"admin"}
Send invalid data and you get your schema's own error messages back:
curl -X POST http://localhost:4000/users \
-H "Content-Type: application/json" \
-d '{"name":"Bad","email":"not-an-email","role":"owner"}'
{"error":"Validation failed","issues":[{"path":"email","message":"Invalid email address"},{"path":"role","message":"Invalid option: expected one of \"admin\"|\"member\""}]}
Update part of a record, then delete it:
curl -X PATCH http://localhost:4000/users/11 -H "Content-Type: application/json" -d '{"role":"member"}'
# {"id":11,"name":"Ada Lovelace","email":"ada@example.com","role":"member"}
curl -X DELETE http://localhost:4000/users/11
# (204 No Content)
curl http://localhost:4000/users/11
# {"error":"users with id 11 not found"}
Validation messages are worded by your Zod version; the examples above are from Zod 4.
Why mockhttpkit
The frontend is ready to build, but the API it needs doesn't exist yet. The usual workarounds are hard-coded JSON files, or a hand-written mock server that drifts out of date. If you already describe your data with Zod, you've written everything a mock needs. mockhttpkit reads those schemas and serves a realistic, validating API from them, so the frontend work isn't blocked on the backend.
CLI reference
mockhttpkit start --schema <file> [options]
| Flag | Default | Description |
|---|---|---|
-s, --schema <file> |
(required) | .ts or .js file exporting Zod schemas. TypeScript is compiled on the fly, with no build step. |
-p, --port <number> |
4000 |
Port to listen on. 0 picks a free port. |
--host <host> |
localhost |
Interface to bind. localhost listens on both 127.0.0.1 and ::1. |
-c, --count <number> |
10 |
Fake records generated per resource (max 100000). |
-d, --delay <ms> |
0 |
Latency added to every response, to test loading states. |
mockhttpkit --help and mockhttpkit start --help print the same reference.
Routes
Each exported z.object() becomes a resource. The name has any trailing Schema removed, is converted to kebab-case, and is pluralised: UserSchema → /users, BlogPost → /blog-posts, Person → /people.
| Method | Path | Behaviour |
|---|---|---|
GET |
/users |
List. ?field=value filters (repeat a field for OR), ?_limit=, ?_offset=. Total count in the X-Total-Count header. |
GET |
/users/:id |
One record, or 404 |
POST |
/users |
Create. Validated by Zod; returns 201, or 400 with the issues |
PUT |
/users/:id |
Replace (validated) |
PATCH |
/users/:id |
Merge into the existing record, then validate |
DELETE |
/users/:id |
Remove; returns 204 |
GET / lists every resource and route. CORS is open, so a dev server on another port can call mockhttpkit directly.
Data lives in memory for the current run. Stop the server and it starts fresh next time.
Using schemas from multiple files
--schema points at a single file, but that file doesn't have to define your schemas directly — it
can just re-export them from wherever they already live in your project:
// mock-schema.ts
export * from './src/models/user';
export * from './src/models/order';
export * from './src/models/product';
npx mockhttpkit start --schema ./mock-schema.ts
Every exported z.object() across all the re-exported files becomes its own resource, exactly as if
they were defined in one file. This means mockhttpkit works the same way on a small project or a large
one with schemas spread across many files — you just point it at one small file that gathers them.
How the fake data is chosen
- By field name.
email,name,firstName,avatar,phone,city,price,createdAt,userId,isActiveand about 60 more map to fitting faker generators. Matching ignores case and separators. - By Zod type and constraints. mockhttpkit respects:
- string checks:
.email(),.url(),.uuid(),.datetime(),.min()/.max()/.length(),.startsWith(); - number checks:
.int(),.positive(),.multipleOf(), and date ranges; - enums, literals, nested objects, arrays, records, unions, and optional or nullable fields.
- string checks:
- Numeric
ids count up from 1. Other ids are UUIDs, or are generated from the id's own schema. Every generated record is checked against your schema. If a rule can't be satisfied automatically, such as a custom.refine()or a.regex(), mockhttpkit prints a one-line warning naming the field.
Compatibility
Because mockhttpkit adheres strictly to standard HTTP/1.1 and RFC 8259 JSON specifications with standard status codes and CORS headers, any language or HTTP client works out of the box without special adapters.
| Language | GET list | GET one | POST | PATCH | DELETE | all pass |
|---|---|---|---|---|---|---|
| JavaScript (native fetch) | PASS | PASS | PASS | PASS | PASS | PASS |
| Python (urllib stdlib) | PASS | PASS | PASS | PASS | PASS | PASS |
| Go (net/http stdlib) | PASS | PASS | PASS | PASS | PASS | PASS |
| Java (java.net.http stdlib) | PASS | PASS | PASS | PASS | PASS | PASS |
| PHP (curl stdlib) | PASS | PASS | PASS | PASS | PASS | PASS |
| Ruby (net/http stdlib) | PASS | PASS | PASS | PASS | PASS | PASS |
| curl (bash baseline) | PASS | PASS | PASS | PASS | PASS | PASS |
Feature requests
Found a bug or want a feature added? Email devnolan.co@gmail.com describing what you need. Upcoming features are planned around what people ask for.