360-mock-server 1.0.0 ā 1.1.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 +49 -14
- package/bin/cli.js +199 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# š Mock
|
|
1
|
+
# š 360 Mock Server
|
|
2
2
|
|
|
3
3
|
Zero-config dynamic mock REST API server. Perfect for frontend development when backend isn't ready.
|
|
4
4
|
|
|
@@ -8,24 +8,58 @@ Zero-config dynamic mock REST API server. Perfect for frontend development when
|
|
|
8
8
|
# Global installation (recommended)
|
|
9
9
|
npm install -g 360-mock-server
|
|
10
10
|
|
|
11
|
-
# Or use npx
|
|
12
|
-
npx 360-mock-server
|
|
11
|
+
# Or use npx (no install needed)
|
|
12
|
+
npx 360-mock-server
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
#
|
|
19
|
-
|
|
18
|
+
# Just run one command - that's it!
|
|
19
|
+
npx 360-mock-server
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This will:
|
|
23
|
+
1. ā
Create `mock-data.json` automatically
|
|
24
|
+
2. ā
Start the server on port 3000
|
|
25
|
+
3. ā
Open interactive mode for easy API requests
|
|
26
|
+
|
|
27
|
+
---
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
360-mock init
|
|
29
|
+
## Interactive Mode (Recommended!)
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
After running `npx 360-mock-server`, you get an interactive prompt:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
360-mock> POST /users {"name": "Ali", "email": "ali@test.com"}
|
|
35
|
+
š¤ POST /users
|
|
36
|
+
ā
Status: 201
|
|
37
|
+
{ "id": 1234567890, "name": "Ali", "email": "ali@test.com" }
|
|
38
|
+
|
|
39
|
+
360-mock> GET /users
|
|
40
|
+
š¤ GET /users
|
|
41
|
+
ā
Status: 200
|
|
42
|
+
[{ "id": 1234567890, "name": "Ali", "email": "ali@test.com" }]
|
|
43
|
+
|
|
44
|
+
360-mock> POST /products {"name": "Laptop", "price": 999}
|
|
45
|
+
360-mock> GET /products
|
|
46
|
+
360-mock> DELETE /users/1234567890
|
|
47
|
+
360-mock> exit
|
|
26
48
|
```
|
|
27
49
|
|
|
28
|
-
|
|
50
|
+
### Interactive Commands
|
|
51
|
+
|
|
52
|
+
| Command | Example |
|
|
53
|
+
|---------|---------|
|
|
54
|
+
| GET | `GET /users` |
|
|
55
|
+
| POST | `POST /users {"name": "Ali"}` |
|
|
56
|
+
| PUT | `PUT /users/123 {"name": "Updated"}` |
|
|
57
|
+
| PATCH | `PATCH /users/123 {"email": "new@test.com"}` |
|
|
58
|
+
| DELETE | `DELETE /users/123` |
|
|
59
|
+
| list | Show all resources |
|
|
60
|
+
| clear | Clear screen |
|
|
61
|
+
| help | Show help |
|
|
62
|
+
| exit | Exit |
|
|
29
63
|
|
|
30
64
|
---
|
|
31
65
|
|
|
@@ -33,7 +67,8 @@ Server runs at `http://localhost:3000`
|
|
|
33
67
|
|
|
34
68
|
| Command | Description |
|
|
35
69
|
|---------|-------------|
|
|
36
|
-
| `360-mock
|
|
70
|
+
| `360-mock` | Start server + interactive mode |
|
|
71
|
+
| `360-mock start` | Start server only |
|
|
37
72
|
| `360-mock init` | Create mock-data.json |
|
|
38
73
|
| `360-mock list` | Show available resources |
|
|
39
74
|
| `360-mock reset` | Clear all data |
|
|
@@ -41,15 +76,15 @@ Server runs at `http://localhost:3000`
|
|
|
41
76
|
### Options
|
|
42
77
|
|
|
43
78
|
```bash
|
|
44
|
-
360-mock
|
|
45
|
-
360-mock
|
|
79
|
+
360-mock --port 4000 # Custom port
|
|
80
|
+
360-mock --file db.json # Custom data file
|
|
46
81
|
360-mock --help # Show help
|
|
47
82
|
360-mock --version # Show version
|
|
48
83
|
```
|
|
49
84
|
|
|
50
85
|
---
|
|
51
86
|
|
|
52
|
-
## API
|
|
87
|
+
## API Endpoints
|
|
53
88
|
|
|
54
89
|
### Any endpoint works automatically!
|
|
55
90
|
|
package/bin/cli.js
CHANGED
|
@@ -3,22 +3,205 @@
|
|
|
3
3
|
const { program } = require("commander");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const fs = require("fs");
|
|
6
|
+
const http = require("http");
|
|
7
|
+
const readline = require("readline");
|
|
6
8
|
|
|
7
9
|
const packageJson = require("../package.json");
|
|
8
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
|
+
|
|
9
160
|
program
|
|
10
161
|
.name("360-mock")
|
|
11
|
-
.description("
|
|
162
|
+
.description("ļæ½š Dynamic Mock REST API Server - Zero Config")
|
|
12
163
|
.version(packageJson.version);
|
|
13
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
|
+
|
|
14
192
|
program
|
|
15
193
|
.command("start")
|
|
16
|
-
.description("Start the mock server")
|
|
194
|
+
.description("Start the mock server only (no interactive mode)")
|
|
17
195
|
.option("-p, --port <port>", "Port number", "3000")
|
|
18
196
|
.option("-f, --file <filename>", "Data file name", "mock-data.json")
|
|
19
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
|
+
}
|
|
20
203
|
process.env.PORT = options.port;
|
|
21
|
-
process.env.DATA_FILE =
|
|
204
|
+
process.env.DATA_FILE = dataFile;
|
|
22
205
|
require("../lib/server");
|
|
23
206
|
});
|
|
24
207
|
|
|
@@ -32,15 +215,9 @@ program
|
|
|
32
215
|
console.log(`ā ļø ${options.file} already exists!`);
|
|
33
216
|
return;
|
|
34
217
|
}
|
|
35
|
-
|
|
36
|
-
_info: "Add your mock data here. Each key becomes an API endpoint.",
|
|
37
|
-
users: [],
|
|
38
|
-
products: []
|
|
39
|
-
};
|
|
40
|
-
fs.writeFileSync(filePath, JSON.stringify(initialData, null, 2));
|
|
218
|
+
fs.writeFileSync(filePath, JSON.stringify({}, null, 2));
|
|
41
219
|
console.log(`ā
Created ${options.file}`);
|
|
42
|
-
console.log(`\n
|
|
43
|
-
console.log(`\nš Run '360-mock start' to start the server`);
|
|
220
|
+
console.log(`\n Run '360-mock' to start the server`);
|
|
44
221
|
});
|
|
45
222
|
|
|
46
223
|
program
|
|
@@ -64,13 +241,13 @@ program
|
|
|
64
241
|
.action((options) => {
|
|
65
242
|
const filePath = path.join(process.cwd(), options.file);
|
|
66
243
|
if (!fs.existsSync(filePath)) {
|
|
67
|
-
console.log(`ā ļø ${options.file} not found
|
|
244
|
+
console.log(`ā ļø ${options.file} not found!`);
|
|
68
245
|
return;
|
|
69
246
|
}
|
|
70
247
|
try {
|
|
71
248
|
const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
72
249
|
const resources = Object.keys(data).filter(k => !k.startsWith("_"));
|
|
73
|
-
console.log(`\nš¦ Available Resources
|
|
250
|
+
console.log(`\nš¦ Available Resources:\n`);
|
|
74
251
|
if (resources.length === 0) {
|
|
75
252
|
console.log(" No resources yet. POST to any endpoint to create one!");
|
|
76
253
|
} else {
|
|
@@ -85,4 +262,13 @@ program
|
|
|
85
262
|
}
|
|
86
263
|
});
|
|
87
264
|
|
|
265
|
+
// API Request command (for non-interactive use)
|
|
266
|
+
program
|
|
267
|
+
.command("req <method> <endpoint> [data]")
|
|
268
|
+
.description("Make single API request")
|
|
269
|
+
.option("-p, --port <port>", "Server port", "3000")
|
|
270
|
+
.action(async (method, endpoint, data, options) => {
|
|
271
|
+
await makeRequest(method, endpoint, data, options.port);
|
|
272
|
+
});
|
|
273
|
+
|
|
88
274
|
program.parse();
|