get-fake-api 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +634 -2
- package/data/auth.js +36 -0
- package/data/orders.js +137 -0
- package/data/posts.js +214 -0
- package/data/products.js +260 -0
- package/data/users.js +377 -0
- package/index.js +74 -0
- package/package.json +31 -4
- package/test.js +113 -0
package/README.md
CHANGED
|
@@ -1,3 +1,635 @@
|
|
|
1
|
-
#
|
|
1
|
+
# get-fake-api 🚀
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Zero-dependency, 100% offline mock data generator for developers. Build, prototype, and test backend REST routes (GET, POST, PATCH, PUT, DELETE) and frontend UI applications without rate limits, API keys, or network latency.
|
|
4
|
+
|
|
5
|
+
[](https://npmjs.com/package/get-fake-api)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[]()
|
|
8
|
+
[]()
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 📌 Table of Contents
|
|
13
|
+
|
|
14
|
+
- [Why get-fake-api?](#-why-get-fake-api)
|
|
15
|
+
- [Installation](#-installation)
|
|
16
|
+
- [Importing](#-importing)
|
|
17
|
+
- [Where Can It Be Used?](#-where-can-it-be-used)
|
|
18
|
+
- [Building REST API Routes (Express Example)](#-building-rest-api-routes-express-example)
|
|
19
|
+
- [GET Routes (Fetch & Filter)](#1-get-routes-fetching--filtering-data)
|
|
20
|
+
- [POST Routes (Create Resource & Login)](#2-post-routes-simulating-resource-creation--auth)
|
|
21
|
+
- [PATCH Routes (Partial Update)](#3-patch-routes-simulating-partial-updates)
|
|
22
|
+
- [PUT Routes (Full Update)](#4-put-routes-simulating-complete-replacement)
|
|
23
|
+
- [DELETE Routes (Remove Resource)](#5-delete-routes-simulating-deletion)
|
|
24
|
+
- [Next.js App Router Example](#-nextjs-app-router-example)
|
|
25
|
+
- [Frontend Prototyping (React / Loading Spinners)](#-frontend-prototyping-react--loading-spinners)
|
|
26
|
+
- [Testing & Mocking (Jest / Vitest / MSW)](#-testing--mocking-jest--vitest--msw)
|
|
27
|
+
- [API Reference & Query Filters](#-api-reference--query-filters)
|
|
28
|
+
- [👤 Users](#-users)
|
|
29
|
+
- [🛍️ Products](#️-products)
|
|
30
|
+
- [📝 Posts & Comments](#-posts--comments)
|
|
31
|
+
- [💳 Orders & Carts](#-orders--carts)
|
|
32
|
+
- [🔑 Authentication & JWT](#-authentication--jwt)
|
|
33
|
+
- [📦 Direct Data Access](#-direct-data-access)
|
|
34
|
+
- [Simulated Async Delays (`fakeApi`)](#-simulated-async-delays-fakeapi)
|
|
35
|
+
- [Contributing & Testing](#-contributing--testing)
|
|
36
|
+
- [License](#-license)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 💡 Why get-fake-api?
|
|
41
|
+
|
|
42
|
+
External mock APIs like JSONPlaceholder or DummyJSON are great, but:
|
|
43
|
+
- ❌ They fail when you are offline, on a flight, or have spotty internet.
|
|
44
|
+
- ❌ They hit rate limits when running large automated test suites.
|
|
45
|
+
- ❌ Network latency can slow down your rapid local development.
|
|
46
|
+
- ❌ You cannot run them synchronously when seeding unit tests.
|
|
47
|
+
|
|
48
|
+
**`get-fake-api` solves this:**
|
|
49
|
+
- 🔌 **100% Offline & Zero Dependencies:** Runs entirely in memory in Node.js or the browser.
|
|
50
|
+
- ⚡ **Synchronous & Asynchronous:** Generate data instantly or simulate real network latency with `fakeApi`.
|
|
51
|
+
- 🛠️ **Dynamic & Extensible:** Request 5, 50, or 500 items on demand with dynamic generation.
|
|
52
|
+
- 🎯 **Realistic Schemas:** Complete with avatars, nested addresses, tags, e-commerce pricing, order statuses, and mock JWT tokens.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 📥 Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# npm
|
|
60
|
+
npm install get-fake-api
|
|
61
|
+
|
|
62
|
+
# yarn
|
|
63
|
+
yarn add get-fake-api
|
|
64
|
+
|
|
65
|
+
# pnpm
|
|
66
|
+
pnpm add get-fake-api
|
|
67
|
+
|
|
68
|
+
# bun
|
|
69
|
+
bun add get-fake-api
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 📦 Importing
|
|
75
|
+
|
|
76
|
+
### CommonJS (Node.js)
|
|
77
|
+
```javascript
|
|
78
|
+
const {
|
|
79
|
+
getUsers,
|
|
80
|
+
getUserById,
|
|
81
|
+
getProducts,
|
|
82
|
+
getProductById,
|
|
83
|
+
getPosts,
|
|
84
|
+
getComments,
|
|
85
|
+
getOrders,
|
|
86
|
+
getAuthToken,
|
|
87
|
+
getAuthSession,
|
|
88
|
+
fakeApi
|
|
89
|
+
} = require("get-fake-api");
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### ES Modules / TypeScript
|
|
93
|
+
```javascript
|
|
94
|
+
import {
|
|
95
|
+
getUsers,
|
|
96
|
+
getUserById,
|
|
97
|
+
getProducts,
|
|
98
|
+
getProductById,
|
|
99
|
+
getPosts,
|
|
100
|
+
getComments,
|
|
101
|
+
getOrders,
|
|
102
|
+
getAuthToken,
|
|
103
|
+
getAuthSession,
|
|
104
|
+
fakeApi
|
|
105
|
+
} from "get-fake-api";
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 🎯 Where Can It Be Used?
|
|
111
|
+
|
|
112
|
+
| Environment | Use Case | Example |
|
|
113
|
+
| :--- | :--- | :--- |
|
|
114
|
+
| **Backend REST APIs** | Mock endpoints before databases are configured | Express, Fastify, Koa, NestJS, Hono |
|
|
115
|
+
| **Full-Stack Frameworks** | Serverless route handlers & API prototyping | Next.js (`app/api`), Remix, Nuxt, SvelteKit |
|
|
116
|
+
| **Frontend UI Prototyping** | Populate tables, dashboards, cards, and carts | React, Vue, Angular, Svelte, Tailwind UI |
|
|
117
|
+
| **Async & Loading UI** | Test skeleton loaders, spinners, and latency | `fakeApi.getUsers({ delay: 500 })` |
|
|
118
|
+
| **Unit & Integration Tests** | Deterministic mock fixtures with zero network calls | Jest, Vitest, Cypress, Playwright |
|
|
119
|
+
| **Mock Service Worker** | Browser and node request interception | MSW handlers |
|
|
120
|
+
| **Mobile Prototyping** | Offline feed and user profile simulation | React Native, Flutter, Expo |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 🚀 Building REST API Routes (Express Example)
|
|
125
|
+
|
|
126
|
+
Here is how you can use `get-fake-api` to build a complete mock REST API handling **GET**, **POST**, **PATCH**, **PUT**, and **DELETE** requests in Express:
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
const express = require("express");
|
|
130
|
+
const {
|
|
131
|
+
getUsers,
|
|
132
|
+
getUserById,
|
|
133
|
+
getProducts,
|
|
134
|
+
getProductById,
|
|
135
|
+
getPosts,
|
|
136
|
+
getOrders,
|
|
137
|
+
getAuthSession
|
|
138
|
+
} = require("get-fake-api");
|
|
139
|
+
|
|
140
|
+
const app = express();
|
|
141
|
+
app.use(express.json());
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 1. GET Routes (Fetching & Filtering Data)
|
|
145
|
+
|
|
146
|
+
Use sync methods to return mock items, filter by query parameters, or find items by ID:
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
// GET /api/users - List users with optional search & filters
|
|
150
|
+
app.get("/api/users", (req, res) => {
|
|
151
|
+
const { count, gender, role, q } = req.query;
|
|
152
|
+
|
|
153
|
+
const users = getUsers({
|
|
154
|
+
count: count ? Number(count) : 10,
|
|
155
|
+
gender,
|
|
156
|
+
role,
|
|
157
|
+
q
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
res.json({ success: true, count: users.length, data: users });
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// GET /api/users/:id - Get single user by ID
|
|
164
|
+
app.get("/api/users/:id", (req, res) => {
|
|
165
|
+
const user = getUserById(req.params.id);
|
|
166
|
+
if (!user) {
|
|
167
|
+
return res.status(404).json({ success: false, message: "User not found" });
|
|
168
|
+
}
|
|
169
|
+
res.json({ success: true, data: user });
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// GET /api/products - Search products with price range & sorting
|
|
173
|
+
app.get("/api/products", (req, res) => {
|
|
174
|
+
const { category, minPrice, maxPrice, sortField, sortOrder, q } = req.query;
|
|
175
|
+
|
|
176
|
+
const products = getProducts({
|
|
177
|
+
category,
|
|
178
|
+
minPrice: minPrice ? Number(minPrice) : undefined,
|
|
179
|
+
maxPrice: maxPrice ? Number(maxPrice) : undefined,
|
|
180
|
+
sortField: sortField || "price",
|
|
181
|
+
sortOrder: sortOrder || "asc",
|
|
182
|
+
q
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
res.json({ success: true, count: products.length, data: products });
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 2. POST Routes (Simulating Resource Creation & Auth)
|
|
190
|
+
|
|
191
|
+
Simulate creating new resources by combining the client's request payload with realistic default schemas and assigning a generated ID:
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
// POST /api/users - Simulate creating a new user
|
|
195
|
+
app.post("/api/users", (req, res) => {
|
|
196
|
+
const { firstName, lastName, email, role } = req.body;
|
|
197
|
+
|
|
198
|
+
if (!firstName || !email) {
|
|
199
|
+
return res.status(400).json({ success: false, message: "First name and email are required" });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Create a realistic mock record merging payload with fallback defaults
|
|
203
|
+
const newUser = {
|
|
204
|
+
id: Date.now(),
|
|
205
|
+
firstName,
|
|
206
|
+
lastName: lastName || "Doe",
|
|
207
|
+
fullName: `${firstName} ${lastName || "Doe"}`,
|
|
208
|
+
username: email.split("@")[0],
|
|
209
|
+
email,
|
|
210
|
+
role: role || "user",
|
|
211
|
+
avatar: "https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=200",
|
|
212
|
+
createdAt: new Date().toISOString()
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
res.status(201).json({
|
|
216
|
+
success: true,
|
|
217
|
+
message: "User created successfully",
|
|
218
|
+
data: newUser
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// POST /api/auth/login - Simulate user authentication and JWT session
|
|
223
|
+
app.post("/api/auth/login", (req, res) => {
|
|
224
|
+
const { email, password } = req.body;
|
|
225
|
+
|
|
226
|
+
if (!email || !password) {
|
|
227
|
+
return res.status(400).json({ success: false, message: "Email and password are required" });
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Generate authentic mock JWT token and session
|
|
231
|
+
const session = getAuthSession({ email, role: "admin" });
|
|
232
|
+
|
|
233
|
+
res.json({
|
|
234
|
+
success: true,
|
|
235
|
+
message: "Login successful",
|
|
236
|
+
session
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 3. PATCH Routes (Simulating Partial Updates)
|
|
242
|
+
|
|
243
|
+
Use `getUserById` or `getProductById` to fetch the baseline record, merge incoming changes, and return the updated entity:
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
// PATCH /api/users/:id - Partial update (e.g. changing email or role)
|
|
247
|
+
app.patch("/api/users/:id", (req, res) => {
|
|
248
|
+
const existingUser = getUserById(req.params.id);
|
|
249
|
+
|
|
250
|
+
if (!existingUser) {
|
|
251
|
+
return res.status(404).json({ success: false, message: "User not found" });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Merge existing entity with updated fields from req.body
|
|
255
|
+
const updatedUser = {
|
|
256
|
+
...existingUser,
|
|
257
|
+
...req.body,
|
|
258
|
+
id: existingUser.id, // preserve original ID
|
|
259
|
+
updatedAt: new Date().toISOString()
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
res.json({
|
|
263
|
+
success: true,
|
|
264
|
+
message: "User updated successfully (PATCH)",
|
|
265
|
+
data: updatedUser
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 4. PUT Routes (Simulating Complete Replacement)
|
|
271
|
+
|
|
272
|
+
Replace a resource while preserving schema integrity:
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
// PUT /api/products/:id - Complete replacement of product
|
|
276
|
+
app.put("/api/products/:id", (req, res) => {
|
|
277
|
+
const existingProduct = getProductById(req.params.id);
|
|
278
|
+
|
|
279
|
+
if (!existingProduct) {
|
|
280
|
+
return res.status(404).json({ success: false, message: "Product not found" });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const replacedProduct = {
|
|
284
|
+
id: existingProduct.id,
|
|
285
|
+
title: req.body.title || "Untitled Product",
|
|
286
|
+
price: req.body.price || 0,
|
|
287
|
+
category: req.body.category || "general",
|
|
288
|
+
description: req.body.description || "",
|
|
289
|
+
stock: req.body.stock ?? 10,
|
|
290
|
+
updatedAt: new Date().toISOString()
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
res.json({
|
|
294
|
+
success: true,
|
|
295
|
+
message: "Product replaced successfully (PUT)",
|
|
296
|
+
data: replacedProduct
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### 5. DELETE Routes (Simulating Deletion)
|
|
302
|
+
|
|
303
|
+
Validate existence and return standard REST deletion responses:
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
// DELETE /api/posts/:id - Delete a post
|
|
307
|
+
app.delete("/api/posts/:id", (req, res) => {
|
|
308
|
+
const postId = Number(req.params.id);
|
|
309
|
+
|
|
310
|
+
res.json({
|
|
311
|
+
success: true,
|
|
312
|
+
message: `Post ${postId} deleted successfully`,
|
|
313
|
+
deletedId: postId
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## ⚡ Next.js App Router Example
|
|
321
|
+
|
|
322
|
+
In Next.js (`app/api/products/route.js` or `.ts`):
|
|
323
|
+
|
|
324
|
+
```javascript
|
|
325
|
+
import { NextResponse } from "next/server";
|
|
326
|
+
import { getProducts } from "get-fake-api";
|
|
327
|
+
|
|
328
|
+
// GET /api/products
|
|
329
|
+
export async function GET(request) {
|
|
330
|
+
const { searchParams } = new URL(request.url);
|
|
331
|
+
const category = searchParams.get("category");
|
|
332
|
+
const count = Number(searchParams.get("count")) || 8;
|
|
333
|
+
|
|
334
|
+
const products = getProducts({ category, count });
|
|
335
|
+
return NextResponse.json(products);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// POST /api/products
|
|
339
|
+
export async function POST(request) {
|
|
340
|
+
const body = await request.json();
|
|
341
|
+
|
|
342
|
+
const newProduct = {
|
|
343
|
+
id: Date.now(),
|
|
344
|
+
...body,
|
|
345
|
+
createdAt: new Date().toISOString()
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
return NextResponse.json(newProduct, { status: 201 });
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## 🎨 Frontend Prototyping (React / Loading Spinners)
|
|
355
|
+
|
|
356
|
+
Use `fakeApi` to simulate real-world async network delays, enabling you to test loading spinners, skeleton UI screens, and state management without spinning up a backend server:
|
|
357
|
+
|
|
358
|
+
```jsx
|
|
359
|
+
import React, { useState, useEffect } from "react";
|
|
360
|
+
import { fakeApi } from "get-fake-api";
|
|
361
|
+
|
|
362
|
+
export default function UserList() {
|
|
363
|
+
const [users, setUsers] = useState([]);
|
|
364
|
+
const [loading, setLoading] = useState(true);
|
|
365
|
+
|
|
366
|
+
useEffect(() => {
|
|
367
|
+
async function loadData() {
|
|
368
|
+
setLoading(true);
|
|
369
|
+
// Simulates a 400ms network roundtrip
|
|
370
|
+
const data = await fakeApi.getUsers({ count: 6, delay: 400 });
|
|
371
|
+
setUsers(data);
|
|
372
|
+
setLoading(false);
|
|
373
|
+
}
|
|
374
|
+
loadData();
|
|
375
|
+
}, []);
|
|
376
|
+
|
|
377
|
+
if (loading) return <div className="spinner">Loading users...</div>;
|
|
378
|
+
|
|
379
|
+
return (
|
|
380
|
+
<div className="user-grid">
|
|
381
|
+
{users.map(u => (
|
|
382
|
+
<div key={u.id} className="card">
|
|
383
|
+
<img src={u.avatar} alt={u.fullName} />
|
|
384
|
+
<h3>{u.fullName}</h3>
|
|
385
|
+
<p>{u.company.title} at {u.company.name}</p>
|
|
386
|
+
<span>{u.email}</span>
|
|
387
|
+
</div>
|
|
388
|
+
))}
|
|
389
|
+
</div>
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## 🧪 Testing & Mocking (Jest / Vitest / MSW)
|
|
397
|
+
|
|
398
|
+
### Jest / Vitest Mocking
|
|
399
|
+
```javascript
|
|
400
|
+
import { getUsers, getAuthToken } from "get-fake-api";
|
|
401
|
+
|
|
402
|
+
test("should authenticate and process 5 users", () => {
|
|
403
|
+
const users = getUsers(5);
|
|
404
|
+
expect(users).toHaveLength(5);
|
|
405
|
+
expect(users[0]).toHaveProperty("email");
|
|
406
|
+
|
|
407
|
+
const token = getAuthToken({ id: users[0].id });
|
|
408
|
+
expect(token.split(".")).toHaveLength(3); // Valid JWT structure
|
|
409
|
+
});
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Mock Service Worker (MSW)
|
|
413
|
+
```javascript
|
|
414
|
+
import { http, HttpResponse } from "msw";
|
|
415
|
+
import { getProducts, getProductById } from "get-fake-api";
|
|
416
|
+
|
|
417
|
+
export const handlers = [
|
|
418
|
+
http.get("https://api.example.com/products", () => {
|
|
419
|
+
return HttpResponse.json(getProducts(12));
|
|
420
|
+
}),
|
|
421
|
+
http.get("https://api.example.com/products/:id", ({ params }) => {
|
|
422
|
+
const product = getProductById(params.id);
|
|
423
|
+
return HttpResponse.json(product);
|
|
424
|
+
})
|
|
425
|
+
];
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 📖 API Reference & Query Filters
|
|
431
|
+
|
|
432
|
+
### 👤 Users
|
|
433
|
+
|
|
434
|
+
```javascript
|
|
435
|
+
const users = getUsers({ count: 10, gender: "female", role: "developer", q: "Sarah" });
|
|
436
|
+
const user = getUserById(1);
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
| Parameter | Type | Default | Description |
|
|
440
|
+
| :--- | :--- | :--- | :--- |
|
|
441
|
+
| `count` / `limit` | `number` | `10` | Total users to return. Generates dynamically if greater than base set. |
|
|
442
|
+
| `gender` | `string` | - | Filter by `"male"` or `"female"`. |
|
|
443
|
+
| `role` | `string` | - | Filter by role (e.g. `"developer"`, `"manager"`, `"designer"`). |
|
|
444
|
+
| `company` | `string` | - | Filter by company name substring. |
|
|
445
|
+
| `q` | `string` | - | Full-text search across `fullName`, `email`, and `username`. |
|
|
446
|
+
|
|
447
|
+
**Sample User Object:**
|
|
448
|
+
```json
|
|
449
|
+
{
|
|
450
|
+
"id": 1,
|
|
451
|
+
"firstName": "Sarah",
|
|
452
|
+
"lastName": "Connor",
|
|
453
|
+
"fullName": "Sarah Connor",
|
|
454
|
+
"username": "sconnor",
|
|
455
|
+
"email": "sarah.connor@example.com",
|
|
456
|
+
"gender": "female",
|
|
457
|
+
"age": 29,
|
|
458
|
+
"phone": "+1-202-555-0143",
|
|
459
|
+
"avatar": "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200",
|
|
460
|
+
"role": "developer",
|
|
461
|
+
"company": {
|
|
462
|
+
"name": "Cyberdyne Systems",
|
|
463
|
+
"title": "Senior Full Stack Engineer",
|
|
464
|
+
"department": "Engineering"
|
|
465
|
+
},
|
|
466
|
+
"address": {
|
|
467
|
+
"street": "742 Evergreen Terrace",
|
|
468
|
+
"city": "Springfield",
|
|
469
|
+
"state": "Oregon",
|
|
470
|
+
"zipCode": "97477",
|
|
471
|
+
"country": "United States"
|
|
472
|
+
},
|
|
473
|
+
"website": "https://sarahconnor.dev"
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
### 🛍️ Products
|
|
480
|
+
|
|
481
|
+
```javascript
|
|
482
|
+
const items = getProducts({
|
|
483
|
+
category: "smartphones",
|
|
484
|
+
minPrice: 200,
|
|
485
|
+
maxPrice: 1000,
|
|
486
|
+
sortField: "price",
|
|
487
|
+
sortOrder: "desc"
|
|
488
|
+
});
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
| Parameter | Type | Default | Description |
|
|
492
|
+
| :--- | :--- | :--- | :--- |
|
|
493
|
+
| `count` / `limit` | `number` | `10` | Number of products to return. |
|
|
494
|
+
| `category` | `string` | - | Categories: `electronics`, `smartphones`, `laptops`, `groceries`, `home-decoration`, `fashion`, `books`, `skincare`. |
|
|
495
|
+
| `brand` | `string` | - | Filter by brand (e.g. `"Apple"`, `"Samsung"`). |
|
|
496
|
+
| `minPrice` | `number` | - | Minimum price filter. |
|
|
497
|
+
| `maxPrice` | `number` | - | Maximum price filter. |
|
|
498
|
+
| `rating` | `number` | - | Minimum rating filter (e.g. `4.5`). |
|
|
499
|
+
| `isAvailable` | `boolean` | - | Filter by stock availability (`stock > 0`). |
|
|
500
|
+
| `sortField` | `string` | - | Field to sort by: `"price"`, `"rating"`, `"stock"`, `"discountPercentage"`. |
|
|
501
|
+
| `sortOrder` | `string` | `"asc"` | `"asc"` or `"desc"`. |
|
|
502
|
+
| `q` | `string` | - | Search keyword in title, description, or brand. |
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
### 📝 Posts & Comments
|
|
507
|
+
|
|
508
|
+
```javascript
|
|
509
|
+
const posts = getPosts({ count: 5, tag: "tech" });
|
|
510
|
+
const singlePost = getPostById(1);
|
|
511
|
+
const comments = getComments({ postId: 1 });
|
|
512
|
+
const postComments = getCommentsByPostId(1);
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
| Parameter | Type | Default | Description |
|
|
516
|
+
| :--- | :--- | :--- | :--- |
|
|
517
|
+
| `count` | `number` | `10` (posts) / `5` (comments) | Quantity to return. |
|
|
518
|
+
| `userId` | `number` | - | Filter posts by author's user ID. |
|
|
519
|
+
| `tag` | `string` | - | Filter by tag (e.g. `"javascript"`, `"react"`, `"productivity"`). |
|
|
520
|
+
| `q` | `string` | - | Search post title and body. |
|
|
521
|
+
| `postId` | `number` | - | Filter comments for a specific post. |
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
### 💳 Orders & Carts
|
|
526
|
+
|
|
527
|
+
```javascript
|
|
528
|
+
const orders = getOrders({ status: "shipped", paymentMethod: "credit_card" });
|
|
529
|
+
const order = getOrderById(1);
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
| Parameter | Type | Default | Description |
|
|
533
|
+
| :--- | :--- | :--- | :--- |
|
|
534
|
+
| `count` | `number` | `4` | Number of orders to return. |
|
|
535
|
+
| `status` | `string` | - | `"pending"`, `"processing"`, `"shipped"`, `"delivered"`, `"cancelled"`. |
|
|
536
|
+
| `userId` | `number` | - | Orders placed by a specific user ID. |
|
|
537
|
+
| `paymentMethod` | `string` | - | `"credit_card"`, `"paypal"`, `"apple_pay"`, `"stripe"`. |
|
|
538
|
+
|
|
539
|
+
Includes `items` array, `totalAmount`, `trackingNumber`, and `createdAt`.
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
### 🔑 Authentication & JWT
|
|
544
|
+
|
|
545
|
+
Generate mock JWT tokens and user session payloads for route protection, testing authentication guards, or mocking login endpoints.
|
|
546
|
+
|
|
547
|
+
```javascript
|
|
548
|
+
// Generate base64url encoded mock JWT string
|
|
549
|
+
const token = getAuthToken({ id: 42, role: "admin" });
|
|
550
|
+
|
|
551
|
+
// Generate full authentication response object
|
|
552
|
+
const session = getAuthSession();
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
**Session Output:**
|
|
556
|
+
```json
|
|
557
|
+
{
|
|
558
|
+
"user": {
|
|
559
|
+
"id": 1,
|
|
560
|
+
"fullName": "Sarah Connor",
|
|
561
|
+
"email": "sarah.connor@example.com",
|
|
562
|
+
"role": "developer"
|
|
563
|
+
},
|
|
564
|
+
"tokenType": "Bearer",
|
|
565
|
+
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
566
|
+
"refreshToken": "mock_refresh_9b8x21729000000",
|
|
567
|
+
"expiresIn": 3600,
|
|
568
|
+
"issuedAt": "2026-10-27T04:00:00.000Z"
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
### 📦 Direct Data Access
|
|
575
|
+
|
|
576
|
+
Access the underlying immutable base mock datasets directly:
|
|
577
|
+
|
|
578
|
+
```javascript
|
|
579
|
+
const { data } = require("get-fake-api");
|
|
580
|
+
|
|
581
|
+
console.log(data.users); // Base users array
|
|
582
|
+
console.log(data.products); // Base products array
|
|
583
|
+
console.log(data.posts); // Base posts array
|
|
584
|
+
console.log(data.comments); // Base comments array
|
|
585
|
+
console.log(data.orders); // Base orders array
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## ⏳ Simulated Async Delays (`fakeApi`)
|
|
591
|
+
|
|
592
|
+
When developing frontends, you often need to test loading states, skeleton screens, and button disable spinners. `fakeApi` wraps synchronous data in a `Promise` with a configurable delay (in milliseconds):
|
|
593
|
+
|
|
594
|
+
```javascript
|
|
595
|
+
const { fakeApi } = require("get-fake-api");
|
|
596
|
+
|
|
597
|
+
// Simulate a 350ms network delay
|
|
598
|
+
const users = await fakeApi.getUsers({ count: 5, delay: 350 });
|
|
599
|
+
|
|
600
|
+
// Simulate fetching a product by ID with 200ms delay
|
|
601
|
+
const product = await fakeApi.getProductById(3, 200);
|
|
602
|
+
|
|
603
|
+
// Simulate a login call
|
|
604
|
+
const session = await fakeApi.login({ email: "user@example.com" }, 500);
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
Available `fakeApi` methods:
|
|
608
|
+
- `fakeApi.getUsers(options)`
|
|
609
|
+
- `fakeApi.getUserById(id, delay)`
|
|
610
|
+
- `fakeApi.getProducts(options)`
|
|
611
|
+
- `fakeApi.getProductById(id, delay)`
|
|
612
|
+
- `fakeApi.getPosts(options)`
|
|
613
|
+
- `fakeApi.getComments(options)`
|
|
614
|
+
- `fakeApi.getOrders(options)`
|
|
615
|
+
- `fakeApi.login(credentials, delay)`
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## 🛠️ Contributing & Testing
|
|
620
|
+
|
|
621
|
+
Run the test suite:
|
|
622
|
+
```bash
|
|
623
|
+
npm test
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
Publishing to npm:
|
|
627
|
+
```bash
|
|
628
|
+
npm publish --access public
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## 📄 License
|
|
634
|
+
|
|
635
|
+
MIT © [yashraj](https://github.com/yashraj)
|
package/data/auth.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { baseUsers } = require("./users");
|
|
2
|
+
|
|
3
|
+
function getAuthToken(payload = {}) {
|
|
4
|
+
const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
|
|
5
|
+
const defaultPayload = {
|
|
6
|
+
sub: payload.id || 1,
|
|
7
|
+
name: payload.fullName || "Sarah Connor",
|
|
8
|
+
email: payload.email || "sarah.connor@example.com",
|
|
9
|
+
role: payload.role || "developer",
|
|
10
|
+
iat: Math.floor(Date.now() / 1000),
|
|
11
|
+
exp: Math.floor(Date.now() / 1000) + 3600
|
|
12
|
+
};
|
|
13
|
+
const body = Buffer.from(JSON.stringify({ ...defaultPayload, ...payload })).toString("base64url");
|
|
14
|
+
const signature = Buffer.from("mock_signature_" + Math.random().toString(36).substring(2)).toString("base64url");
|
|
15
|
+
return `${header}.${body}.${signature}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getAuthSession(user = null) {
|
|
19
|
+
const selectedUser = user || baseUsers[0];
|
|
20
|
+
const accessToken = getAuthToken(selectedUser);
|
|
21
|
+
const refreshToken = `mock_refresh_${Math.random().toString(36).substring(2)}${Date.now()}`;
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
user: selectedUser,
|
|
25
|
+
tokenType: "Bearer",
|
|
26
|
+
accessToken,
|
|
27
|
+
refreshToken,
|
|
28
|
+
expiresIn: 3600,
|
|
29
|
+
issuedAt: new Date().toISOString()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
getAuthToken,
|
|
35
|
+
getAuthSession
|
|
36
|
+
};
|