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.
- package/README.md +148 -116
- package/bin/cli.js +193 -72
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,183 +1,215 @@
|
|
|
1
|
-
# π Mock
|
|
1
|
+
# π 360 Mock Server
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
8
|
-
# Global installation (recommended)
|
|
9
|
-
npm install -g 360-mock-server
|
|
7
|
+
## β¨ Why 360 Mock Server?
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
18
|
-
# Navigate to your project
|
|
19
|
-
cd my-frontend-project
|
|
16
|
+
## π¦ Installation
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
360-mock init
|
|
18
|
+
Install globally using npm:
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
360-mock
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g 360-mock-server
|
|
26
22
|
```
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
Or run directly using `npx` (recommended):
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
31
|
+
## β‘ Quick Start
|
|
43
32
|
|
|
44
33
|
```bash
|
|
45
|
-
360-mock
|
|
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
|
-
|
|
40
|
+
```
|
|
41
|
+
http://localhost:3000
|
|
42
|
+
```
|
|
54
43
|
|
|
55
|
-
Use the built-in `req` command instead of curl:
|
|
56
44
|
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
68
|
-
360-mock
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
54
|
+
360-mock> GET /users
|
|
55
|
+
β
Status: 200
|
|
56
|
+
[{"id": 1737745200000, "name": "Ali", "email": "ali@test.com"}]
|
|
73
57
|
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
360-mock> DELETE /users/1737745200000
|
|
59
|
+
β
Status: 200
|
|
76
60
|
```
|
|
77
61
|
|
|
78
|
-
---
|
|
79
62
|
|
|
80
|
-
##
|
|
63
|
+
## π CLI Commands (Interactive Mode)
|
|
81
64
|
|
|
82
|
-
|
|
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
|
-
|
|
78
|
+
## π§ͺ Using with Postman / REST Clients
|
|
79
|
+
|
|
80
|
+
**Base URL**
|
|
85
81
|
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
POST /users
|
|
89
|
-
POST /products
|
|
90
|
-
POST /orders
|
|
91
|
-
POST /anything-you-want
|
|
82
|
+
```
|
|
83
|
+
http://localhost:3000
|
|
92
84
|
```
|
|
93
85
|
|
|
94
|
-
###
|
|
86
|
+
### Example Endpoints
|
|
95
87
|
|
|
96
|
-
| Method | Endpoint
|
|
97
|
-
|
|
98
|
-
| GET
|
|
99
|
-
| GET
|
|
100
|
-
| POST
|
|
101
|
-
| PUT
|
|
102
|
-
| PATCH
|
|
103
|
-
| DELETE | `/users/
|
|
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
|
-
|
|
97
|
+
**Required Headers**
|
|
107
98
|
|
|
108
|
-
```
|
|
109
|
-
|
|
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
|
-
|
|
106
|
+
<details open>
|
|
107
|
+
<summary><strong>Fetch API</strong></summary>
|
|
120
108
|
|
|
121
109
|
```javascript
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
})
|
|
128
|
-
|
|
129
|
-
// Read all
|
|
130
|
-
const users = await fetch('http://localhost:3000/users').then(r => r.json());
|
|
117
|
+
});
|
|
131
118
|
|
|
132
|
-
//
|
|
133
|
-
const
|
|
119
|
+
// READ
|
|
120
|
+
const users = await fetch(`${API}/users`).then(res => res.json());
|
|
134
121
|
|
|
135
|
-
//
|
|
136
|
-
await fetch(
|
|
122
|
+
// UPDATE
|
|
123
|
+
await fetch(`${API}/users/123`, {
|
|
137
124
|
method: 'PATCH',
|
|
138
125
|
headers: { 'Content-Type': 'application/json' },
|
|
139
|
-
body: JSON.stringify({ name: '
|
|
126
|
+
body: JSON.stringify({ name: 'Updated' })
|
|
140
127
|
});
|
|
141
128
|
|
|
142
|
-
//
|
|
143
|
-
await fetch(
|
|
129
|
+
// DELETE
|
|
130
|
+
await fetch(`${API}/users/123`, { method: 'DELETE' });
|
|
144
131
|
```
|
|
145
132
|
|
|
146
|
-
|
|
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
|
-
|
|
153
|
-
const { data: user } = await api.post('/users', { name: 'Ali' });
|
|
141
|
+
const API = 'http://localhost:3000';
|
|
154
142
|
|
|
155
|
-
//
|
|
156
|
-
|
|
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
|
-
|
|
159
|
-
await api.patch(`/users/${id}`, { name: 'Updated' });
|
|
161
|
+
</details>
|
|
160
162
|
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
##
|
|
179
|
+
## π Additional Commands
|
|
168
180
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
174
|
-
-
|
|
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
|
-
##
|
|
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("
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
.
|
|
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
|
-
|
|
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();
|