360-mock-server 1.0.1 β†’ 1.1.1

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.
Files changed (3) hide show
  1. package/README.md +148 -116
  2. package/bin/cli.js +193 -72
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,183 +1,215 @@
1
- # πŸš€ Mock API Server
1
+ # πŸš€ 360 Mock Server
2
2
 
3
- Zero-config dynamic mock REST API server. Perfect for frontend development when backend isn't ready.
3
+ **360 Mock Server** is a zero-configuration mock REST API designed for frontend developers.
4
+ It allows you to instantly create and manage RESTful APIs **without building a backend**, making it ideal for frontend development, testing, demos, and rapid prototyping.
4
5
 
5
- ## Installation
6
6
 
7
- ```bash
8
- # Global installation (recommended)
9
- npm install -g 360-mock-server
7
+ ## ✨ Why 360 Mock Server?
10
8
 
11
- # Or use npx directly
12
- npx 360-mock-server start
13
- ```
9
+ * No backend setup required
10
+ * Works instantly with **any endpoint**
11
+ * Interactive CLI + REST API
12
+ * Persistent JSON-based storage
13
+ * Ideal for React, React Native, Vue, Angular, Redux apps
14
14
 
15
- ## Quick Start
16
15
 
17
- ```bash
18
- # Navigate to your project
19
- cd my-frontend-project
16
+ ## πŸ“¦ Installation
20
17
 
21
- # Initialize (creates mock-data.json)
22
- 360-mock init
18
+ Install globally using npm:
23
19
 
24
- # Start server
25
- 360-mock start
20
+ ```bash
21
+ npm install -g 360-mock-server
26
22
  ```
27
23
 
28
- Server runs at `http://localhost:3000`
24
+ Or run directly using `npx` (recommended):
29
25
 
30
- ---
31
-
32
- ## CLI Commands
26
+ ```bash
27
+ npx 360-mock-server
28
+ ```
33
29
 
34
- | Command | Description |
35
- |---------|-------------|
36
- | `360-mock start` | Start the server |
37
- | `360-mock init` | Create mock-data.json |
38
- | `360-mock list` | Show available resources |
39
- | `360-mock reset` | Clear all data |
40
- | `360-mock req` | Make API requests |
41
30
 
42
- ### Options
31
+ ## ⚑ Quick Start
43
32
 
44
33
  ```bash
45
- 360-mock start --port 4000 # Custom port
46
- 360-mock start --file db.json # Custom data file
47
- 360-mock --help # Show help
48
- 360-mock --version # Show version
34
+ npx 360-mock-server
49
35
  ```
50
36
 
51
- ---
37
+ That’s it! πŸŽ‰
38
+ The mock server will start at:
52
39
 
53
- ## Making API Requests (Easy Way!)
40
+ ```
41
+ http://localhost:3000
42
+ ```
54
43
 
55
- Use the built-in `req` command instead of curl:
56
44
 
57
- ```bash
58
- # CREATE
59
- 360-mock req POST /users '{"name": "Ali", "email": "ali@test.com"}'
60
- 360-mock req POST /products '{"name": "Laptop", "price": 999}'
61
- 360-mock req POST /orders '{"product": "Laptop", "qty": 2}'
45
+ ## 🧠 Interactive CLI Mode
62
46
 
63
- # READ ALL
64
- 360-mock req GET /users
65
- 360-mock req GET /products
47
+ Once the server starts, you can interact with it directly from the terminal:
66
48
 
67
- # READ ONE
68
- 360-mock req GET /users/1234567890
49
+ ```text
50
+ 360-mock> POST /users {"name": "Ali", "email": "ali@test.com"}
51
+ βœ… Status: 201
52
+ {"id": 1737745200000, "name": "Ali", "email": "ali@test.com"}
69
53
 
70
- # UPDATE
71
- 360-mock req PUT /users/1234567890 '{"name": "Ali Khan"}'
72
- 360-mock req PATCH /users/1234567890 '{"email": "ali.khan@test.com"}'
54
+ 360-mock> GET /users
55
+ βœ… Status: 200
56
+ [{"id": 1737745200000, "name": "Ali", "email": "ali@test.com"}]
73
57
 
74
- # DELETE
75
- 360-mock req DELETE /users/1234567890
58
+ 360-mock> DELETE /users/1737745200000
59
+ βœ… Status: 200
76
60
  ```
77
61
 
78
- ---
79
62
 
80
- ## API Endpoints
63
+ ## πŸ“Ÿ CLI Commands (Interactive Mode)
81
64
 
82
- ### Any endpoint works automatically!
65
+ | Command | Description |
66
+ | -------------------------------------- | ---------------------------- |
67
+ | `GET /users` | Fetch all users |
68
+ | `GET /users/123` | Fetch user by ID |
69
+ | `POST /users {"name":"Ali"}` | Create a new user |
70
+ | `PUT /users/123 {"name":"New"}` | Replace entire resource |
71
+ | `PATCH /users/123 {"email":"x@y.com"}` | Update specific fields |
72
+ | `DELETE /users/123` | Delete resource |
73
+ | `list` | Show all available resources |
74
+ | `clear` | Clear terminal screen |
75
+ | `help` | Show help |
76
+ | `exit` | Exit interactive mode |
83
77
 
84
- Just POST to any endpoint - it creates the resource:
78
+ ## πŸ§ͺ Using with Postman / REST Clients
79
+
80
+ **Base URL**
85
81
 
86
- ```bash
87
- # These all work without configuration:
88
- POST /users
89
- POST /products
90
- POST /orders
91
- POST /anything-you-want
82
+ ```
83
+ http://localhost:3000
92
84
  ```
93
85
 
94
- ### Full CRUD Operations
86
+ ### Example Endpoints
95
87
 
96
- | Method | Endpoint | Description |
97
- |--------|----------|-------------|
98
- | GET | `/users` | Get all users |
99
- | GET | `/users/1` | Get user by ID |
100
- | POST | `/users` | Create user |
101
- | PUT | `/users/1` | Replace user |
102
- | PATCH | `/users/1` | Update user |
103
- | DELETE | `/users/1` | Delete user |
104
- | DELETE | `/users` | Delete all users |
88
+ | Method | Endpoint | Body |
89
+ | ------ | ------------ | ----------------------------- |
90
+ | GET | `/users` | β€” |
91
+ | GET | `/users/123` | β€” |
92
+ | POST | `/users` | `{ "name": "Ali" }` |
93
+ | PUT | `/users/123` | `{ "name": "Updated" }` |
94
+ | PATCH | `/users/123` | `{ "email": "new@test.com" }` |
95
+ | DELETE | `/users/123` | β€” |
105
96
 
106
- ### Query Parameters
97
+ **Required Headers**
107
98
 
108
- ```bash
109
- GET /users?name=john # Filter by name
110
- GET /users?_sort=name # Sort by field
111
- GET /users?_order=desc # Sort order
112
- GET /users?_limit=10&_page=2 # Pagination
99
+ ```
100
+ Content-Type: application/json
113
101
  ```
114
102
 
115
- ---
116
103
 
117
- ## Frontend Examples
104
+ ## πŸ”Œ Frontend Integration Examples
118
105
 
119
- ### Fetch API
106
+ <details open>
107
+ <summary><strong>Fetch API</strong></summary>
120
108
 
121
109
  ```javascript
122
- // Create
123
- const user = await fetch('http://localhost:3000/users', {
110
+ const API = 'http://localhost:3000';
111
+
112
+ // CREATE
113
+ await fetch(`${API}/users`, {
124
114
  method: 'POST',
125
115
  headers: { 'Content-Type': 'application/json' },
126
116
  body: JSON.stringify({ name: 'Ali', email: 'ali@test.com' })
127
- }).then(r => r.json());
128
-
129
- // Read all
130
- const users = await fetch('http://localhost:3000/users').then(r => r.json());
117
+ });
131
118
 
132
- // Read one
133
- const user = await fetch('http://localhost:3000/users/1').then(r => r.json());
119
+ // READ
120
+ const users = await fetch(`${API}/users`).then(res => res.json());
134
121
 
135
- // Update
136
- await fetch('http://localhost:3000/users/1', {
122
+ // UPDATE
123
+ await fetch(`${API}/users/123`, {
137
124
  method: 'PATCH',
138
125
  headers: { 'Content-Type': 'application/json' },
139
- body: JSON.stringify({ name: 'Ali Updated' })
126
+ body: JSON.stringify({ name: 'Updated' })
140
127
  });
141
128
 
142
- // Delete
143
- await fetch('http://localhost:3000/users/1', { method: 'DELETE' });
129
+ // DELETE
130
+ await fetch(`${API}/users/123`, { method: 'DELETE' });
144
131
  ```
145
132
 
146
- ### Axios
133
+ </details>
134
+
135
+ <details>
136
+ <summary><strong>Axios</strong></summary>
147
137
 
148
138
  ```javascript
149
139
  import axios from 'axios';
150
- const api = axios.create({ baseURL: 'http://localhost:3000' });
151
140
 
152
- // Create
153
- const { data: user } = await api.post('/users', { name: 'Ali' });
141
+ const API = 'http://localhost:3000';
154
142
 
155
- // Read
156
- const { data: users } = await api.get('/users');
143
+ // CREATE
144
+ await axios.post(`${API}/users`, {
145
+ name: 'Ali',
146
+ email: 'ali@test.com'
147
+ });
148
+
149
+ // READ
150
+ const { data: users } = await axios.get(`${API}/users`);
151
+
152
+ // UPDATE
153
+ await axios.patch(`${API}/users/123`, {
154
+ name: 'Updated'
155
+ });
156
+
157
+ // DELETE
158
+ await axios.delete(`${API}/users/123`);
159
+ ```
157
160
 
158
- // Update
159
- await api.patch(`/users/${id}`, { name: 'Updated' });
161
+ </details>
160
162
 
161
- // Delete
162
- await api.delete(`/users/${id}`);
163
+
164
+ ## βš™οΈ CLI Options
165
+
166
+ | Option | Description | Default |
167
+ | -------- | -------------- | ---------------- |
168
+ | `--port` | Server port | `3000` |
169
+ | `--file` | Data file name | `mock-data.json` |
170
+
171
+ ### Examples
172
+
173
+ ```bash
174
+ npx 360-mock-server --port 4000
175
+ npx 360-mock-server --file db.json
163
176
  ```
164
177
 
165
- ---
166
178
 
167
- ## Features
179
+ ## πŸ›  Additional Commands
168
180
 
169
- - βœ… **Zero config** - Works out of the box
170
- - βœ… **Any endpoint** - Auto-creates resources
171
- - βœ… **Full CRUD** - GET, POST, PUT, PATCH, DELETE
172
- - βœ… **Filtering** - Query parameter support
173
- - βœ… **Sorting** - `?_sort=field&_order=desc`
174
- - βœ… **Pagination** - `?_limit=10&_page=1`
175
- - βœ… **Auto IDs** - Generated automatically
176
- - βœ… **Timestamps** - createdAt, updatedAt
177
- - βœ… **CORS enabled** - Works with any frontend
181
+ | Command | Description |
182
+ | ---------------- | --------------------------------------- |
183
+ | `360-mock start` | Start server only (no interactive mode) |
184
+ | `360-mock init` | Create an empty data file |
185
+ | `360-mock list` | List all resources |
186
+ | `360-mock reset` | Clear all stored data |
178
187
 
179
- ---
180
188
 
181
- ## License
189
+ ## 🌟 Features
190
+
191
+ * βœ… Zero-config setup
192
+ * βœ… Supports **any REST endpoint**
193
+ * βœ… Full CRUD operations
194
+ * βœ… Auto-generated unique IDs
195
+ * βœ… Automatic timestamps (`createdAt`, `updatedAt`)
196
+ * βœ… Persistent JSON storage
197
+ * βœ… CORS enabled
198
+ * βœ… Works with Postman & frontend apps
199
+ * βœ… Perfect for mock APIs & demos
200
+
201
+
202
+ ## πŸ’Ύ Data Storage
203
+
204
+ All data is stored locally in:
205
+
206
+ ```
207
+ mock-data.json
208
+ ```
209
+
210
+ This file is automatically created and updated in your project directory.
211
+
212
+ ## πŸ“„ License
182
213
 
183
214
  MIT Β© [zahidrahimoon](https://github.com/zahidrahimoon)
215
+
package/bin/cli.js CHANGED
@@ -4,22 +4,204 @@ const { program } = require("commander");
4
4
  const path = require("path");
5
5
  const fs = require("fs");
6
6
  const http = require("http");
7
+ const readline = require("readline");
7
8
 
8
9
  const packageJson = require("../package.json");
9
10
 
11
+ // Helper function for making HTTP requests
12
+ function makeRequest(method, endpoint, data, port = "3000") {
13
+ return new Promise((resolve) => {
14
+ const upperMethod = method.toUpperCase();
15
+ const urlPath = endpoint.startsWith("/") ? endpoint : "/" + endpoint;
16
+
17
+ let jsonData = null;
18
+ if (data) {
19
+ try {
20
+ jsonData = typeof data === "string" ? JSON.parse(data) : data;
21
+ } catch (e) {
22
+ console.log(`❌ Invalid JSON: ${data}`);
23
+ return resolve();
24
+ }
25
+ }
26
+
27
+ const reqOptions = {
28
+ hostname: "localhost",
29
+ port: port,
30
+ path: urlPath,
31
+ method: upperMethod,
32
+ headers: { "Content-Type": "application/json" },
33
+ };
34
+
35
+ console.log(`\nπŸ“€ ${upperMethod} ${urlPath}`);
36
+ if (jsonData) {
37
+ console.log(` Body: ${JSON.stringify(jsonData)}`);
38
+ }
39
+
40
+ const req = http.request(reqOptions, (res) => {
41
+ let body = "";
42
+ res.on("data", (chunk) => { body += chunk; });
43
+ res.on("end", () => {
44
+ const emoji = res.statusCode >= 200 && res.statusCode < 300 ? "βœ…" : "❌";
45
+ console.log(`${emoji} Status: ${res.statusCode}`);
46
+ try {
47
+ const json = JSON.parse(body);
48
+ console.log(JSON.stringify(json, null, 2));
49
+ } catch {
50
+ console.log(body);
51
+ }
52
+ console.log("");
53
+ resolve();
54
+ });
55
+ });
56
+
57
+ req.on("error", (error) => {
58
+ console.error(`❌ Error: ${error.message}`);
59
+ console.log("πŸ’‘ Make sure server is running in another terminal: 360-mock start\n");
60
+ resolve();
61
+ });
62
+
63
+ if (jsonData) req.write(JSON.stringify(jsonData));
64
+ req.end();
65
+ });
66
+ }
67
+
68
+ // Interactive REPL mode
69
+ function startInteractiveMode(port) {
70
+ const rl = readline.createInterface({
71
+ input: process.stdin,
72
+ output: process.stdout,
73
+ });
74
+
75
+ console.log(`
76
+ ╔═══════════════════════════════════════════════════════════╗
77
+ β•‘ πŸš€ 360 Mock Server - Interactive Mode β•‘
78
+ ╠═══════════════════════════════════════════════════════════╣
79
+ β•‘ Server: http://localhost:${port} β•‘
80
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
81
+
82
+ πŸ“Œ Commands:
83
+ GET /users - Get all users
84
+ GET /users/123 - Get user by ID
85
+ POST /users {"name":"Ali"} - Create user
86
+ PUT /users/123 {"name":"Updated"} - Replace user
87
+ PATCH /users/123 {"name":"New"} - Update user
88
+ DELETE /users/123 - Delete user
89
+
90
+ list - Show resources
91
+ clear - Clear screen
92
+ help - Show this help
93
+ exit - Exit
94
+
95
+ `);
96
+
97
+ const prompt = () => {
98
+ rl.question("360-mock> ", async (input) => {
99
+ const trimmed = input.trim();
100
+
101
+ if (!trimmed) {
102
+ prompt();
103
+ return;
104
+ }
105
+
106
+ // Handle special commands
107
+ if (trimmed === "exit" || trimmed === "quit") {
108
+ console.log("οΏ½ Goodbye!");
109
+ rl.close();
110
+ process.exit(0);
111
+ }
112
+
113
+ if (trimmed === "help") {
114
+ console.log(`
115
+ πŸ“Œ Commands:
116
+ GET /users - Get all users
117
+ GET /users/123 - Get user by ID
118
+ POST /users {"name":"Ali"} - Create user
119
+ PUT /users/123 {"name":"Updated"} - Replace user
120
+ PATCH /users/123 {"name":"New"} - Update user
121
+ DELETE /users/123 - Delete user
122
+
123
+ list - Show resources
124
+ clear - Clear screen
125
+ exit - Exit
126
+ `);
127
+ prompt();
128
+ return;
129
+ }
130
+
131
+ if (trimmed === "clear" || trimmed === "cls") {
132
+ console.clear();
133
+ prompt();
134
+ return;
135
+ }
136
+
137
+ if (trimmed === "list") {
138
+ await makeRequest("GET", "/", null, port);
139
+ prompt();
140
+ return;
141
+ }
142
+
143
+ // Parse API request: METHOD /endpoint {json}
144
+ const match = trimmed.match(/^(GET|POST|PUT|PATCH|DELETE)\s+(\/\S*)\s*(.*)$/i);
145
+
146
+ if (match) {
147
+ const [, method, endpoint, jsonStr] = match;
148
+ await makeRequest(method, endpoint, jsonStr || null, port);
149
+ } else {
150
+ console.log(`❌ Invalid command. Type 'help' for usage.\n`);
151
+ }
152
+
153
+ prompt();
154
+ });
155
+ };
156
+
157
+ prompt();
158
+ }
159
+
10
160
  program
11
161
  .name("360-mock")
12
- .description("πŸš€ Dynamic Mock REST API Server - Zero Config")
162
+ .description("οΏ½πŸš€ Dynamic Mock REST API Server - Zero Config")
13
163
  .version(packageJson.version);
14
164
 
165
+ // Default command - start interactive mode
166
+ program
167
+ .command("run", { isDefault: true })
168
+ .description("Start server + interactive mode (recommended)")
169
+ .option("-p, --port <port>", "Port number", "3000")
170
+ .option("-f, --file <filename>", "Data file name", "mock-data.json")
171
+ .action((options) => {
172
+ const dataFile = path.join(process.cwd(), options.file);
173
+
174
+ // Create data file if not exists
175
+ if (!fs.existsSync(dataFile)) {
176
+ fs.writeFileSync(dataFile, JSON.stringify({}, null, 2));
177
+ console.log(`βœ… Created ${options.file}`);
178
+ }
179
+
180
+ process.env.PORT = options.port;
181
+ process.env.DATA_FILE = dataFile;
182
+
183
+ // Start server
184
+ require("../lib/server");
185
+
186
+ // Start interactive mode after a short delay
187
+ setTimeout(() => {
188
+ startInteractiveMode(options.port);
189
+ }, 500);
190
+ });
191
+
15
192
  program
16
193
  .command("start")
17
- .description("Start the mock server")
194
+ .description("Start the mock server only (no interactive mode)")
18
195
  .option("-p, --port <port>", "Port number", "3000")
19
196
  .option("-f, --file <filename>", "Data file name", "mock-data.json")
20
197
  .action((options) => {
198
+ const dataFile = path.join(process.cwd(), options.file);
199
+ if (!fs.existsSync(dataFile)) {
200
+ fs.writeFileSync(dataFile, JSON.stringify({}, null, 2));
201
+ console.log(`βœ… Created ${options.file}`);
202
+ }
21
203
  process.env.PORT = options.port;
22
- process.env.DATA_FILE = path.join(process.cwd(), options.file);
204
+ process.env.DATA_FILE = dataFile;
23
205
  require("../lib/server");
24
206
  });
25
207
 
@@ -33,15 +215,9 @@ program
33
215
  console.log(`⚠️ ${options.file} already exists!`);
34
216
  return;
35
217
  }
36
- const initialData = {
37
- _info: "Add your mock data here. Each key becomes an API endpoint.",
38
- users: [],
39
- products: []
40
- };
41
- fs.writeFileSync(filePath, JSON.stringify(initialData, null, 2));
218
+ fs.writeFileSync(filePath, JSON.stringify({}, null, 2));
42
219
  console.log(`βœ… Created ${options.file}`);
43
- console.log(`\nπŸ“ File location: ${filePath}`);
44
- console.log(`\nπŸš€ Run '360-mock start' to start the server`);
220
+ console.log(`\n Run '360-mock' to start the server`);
45
221
  });
46
222
 
47
223
  program
@@ -65,13 +241,13 @@ program
65
241
  .action((options) => {
66
242
  const filePath = path.join(process.cwd(), options.file);
67
243
  if (!fs.existsSync(filePath)) {
68
- console.log(`⚠️ ${options.file} not found! Run '360-mock init' first.`);
244
+ console.log(`⚠️ ${options.file} not found!`);
69
245
  return;
70
246
  }
71
247
  try {
72
248
  const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
73
249
  const resources = Object.keys(data).filter(k => !k.startsWith("_"));
74
- console.log(`\nπŸ“¦ Available Resources in ${options.file}:\n`);
250
+ console.log(`\nπŸ“¦ Available Resources:\n`);
75
251
  if (resources.length === 0) {
76
252
  console.log(" No resources yet. POST to any endpoint to create one!");
77
253
  } else {
@@ -86,68 +262,13 @@ program
86
262
  }
87
263
  });
88
264
 
89
- // API Request command
265
+ // API Request command (for non-interactive use)
90
266
  program
91
267
  .command("req <method> <endpoint> [data]")
92
- .alias("request")
93
- .description("Make API request (GET, POST, PUT, PATCH, DELETE)")
268
+ .description("Make single API request")
94
269
  .option("-p, --port <port>", "Server port", "3000")
95
- .action((method, endpoint, data, options) => {
96
- const upperMethod = method.toUpperCase();
97
- const path = endpoint.startsWith("/") ? endpoint : "/" + endpoint;
98
-
99
- let jsonData = null;
100
- if (data) {
101
- try {
102
- jsonData = JSON.parse(data);
103
- } catch (e) {
104
- console.log(`❌ Invalid JSON: ${data}`);
105
- process.exit(1);
106
- }
107
- }
108
-
109
- const reqOptions = {
110
- hostname: "localhost",
111
- port: options.port,
112
- path: path,
113
- method: upperMethod,
114
- headers: {
115
- "Content-Type": "application/json",
116
- },
117
- };
118
-
119
- console.log(`\nπŸ“€ ${upperMethod} ${path}`);
120
- if (jsonData) {
121
- console.log(` Body: ${JSON.stringify(jsonData, null, 2)}`);
122
- }
123
- console.log("");
124
-
125
- const req = http.request(reqOptions, (res) => {
126
- let body = "";
127
- res.on("data", (chunk) => { body += chunk; });
128
- res.on("end", () => {
129
- const statusEmoji = res.statusCode >= 200 && res.statusCode < 300 ? "βœ…" : "❌";
130
- console.log(`${statusEmoji} Status: ${res.statusCode}`);
131
- console.log(`πŸ“₯ Response:`);
132
- try {
133
- const json = JSON.parse(body);
134
- console.log(JSON.stringify(json, null, 2));
135
- } catch {
136
- console.log(body);
137
- }
138
- console.log("");
139
- });
140
- });
141
-
142
- req.on("error", (error) => {
143
- console.error(`❌ Error: ${error.message}`);
144
- console.log("\nπŸ’‘ Make sure the server is running: 360-mock start\n");
145
- });
146
-
147
- if (jsonData) {
148
- req.write(JSON.stringify(jsonData));
149
- }
150
- req.end();
270
+ .action(async (method, endpoint, data, options) => {
271
+ await makeRequest(method, endpoint, data, options.port);
151
272
  });
152
273
 
153
274
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "360-mock-server",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "πŸš€ Zero-config dynamic mock REST API server for frontend developers",
5
5
  "main": "lib/server.js",
6
6
  "bin": {