json-api-mocker 1.0.3 → 1.2.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/CONFIG.ch.md +305 -0
- package/CONFIG.md +271 -0
- package/README.ch.md +104 -3
- package/README.md +99 -0
- package/dist/server.d.ts +2 -7
- package/dist/server.js +42 -99
- package/dist/types.d.ts +7 -2
- package/package.json +7 -3
package/CONFIG.ch.md
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
# JSON API Mocker 配置指南
|
2
|
+
|
3
|
+
本文档将帮助你理解和编写 `data.json` 配置文件。
|
4
|
+
|
5
|
+
## 配置文件结构
|
6
|
+
|
7
|
+
```json
|
8
|
+
{
|
9
|
+
"server": {
|
10
|
+
"port": 8080,
|
11
|
+
"baseProxy": "/api"
|
12
|
+
},
|
13
|
+
"routes": []
|
14
|
+
}
|
15
|
+
```
|
16
|
+
|
17
|
+
## 配置项详解
|
18
|
+
|
19
|
+
### 1. 服务器配置 (server)
|
20
|
+
|
21
|
+
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|
22
|
+
|------|------|------|--------|------|
|
23
|
+
| port | number | 否 | 8080 | 服务器端口号 |
|
24
|
+
| baseProxy | string | 否 | "/api" | API 的基础路径 |
|
25
|
+
|
26
|
+
### 2. 路由配置 (routes)
|
27
|
+
|
28
|
+
routes 是一个数组,每个元素都是一个路由配置对象:
|
29
|
+
|
30
|
+
```json
|
31
|
+
{
|
32
|
+
"path": "/users",
|
33
|
+
"methods": {
|
34
|
+
"get": {},
|
35
|
+
"post": {},
|
36
|
+
"put": {},
|
37
|
+
"delete": {}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
```
|
41
|
+
|
42
|
+
#### 2.1 路由基础配置
|
43
|
+
|
44
|
+
| 字段 | 类型 | 必填 | 说明 |
|
45
|
+
|------|------|------|------|
|
46
|
+
| path | string | 是 | 路由路径,支持参数如 `/users/:id` |
|
47
|
+
| methods | object | 是 | HTTP 方法配置对象 |
|
48
|
+
|
49
|
+
#### 2.2 方法配置 (methods)
|
50
|
+
|
51
|
+
每个 HTTP 方法可以包含以下配置:
|
52
|
+
|
53
|
+
| 字段 | 类型 | 必填 | 说明 |
|
54
|
+
|------|------|------|------|
|
55
|
+
| type | string | 否 | 响应类型:"array" 或 "object" |
|
56
|
+
| response | any | 否 | 静态响应数据 |
|
57
|
+
| mock | object | 否 | Mock.js 配置 |
|
58
|
+
| pagination | object | 否 | 分页配置 |
|
59
|
+
| requestSchema | object | 否 | 请求体验证模式 |
|
60
|
+
|
61
|
+
### 3. Mock 数据配置 (mock)
|
62
|
+
|
63
|
+
```json
|
64
|
+
{
|
65
|
+
"mock": {
|
66
|
+
"enabled": true,
|
67
|
+
"total": 100,
|
68
|
+
"template": {
|
69
|
+
"id|+1": 1,
|
70
|
+
"name": "@cname",
|
71
|
+
"email": "@email"
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
```
|
76
|
+
|
77
|
+
| 字段 | 类型 | 必填 | 说明 |
|
78
|
+
|------|------|------|------|
|
79
|
+
| enabled | boolean | 是 | 是否启用 mock 数据 |
|
80
|
+
| total | number | 是 | 生成数据的总条数 |
|
81
|
+
| template | object | 是 | Mock.js 的数据模板 |
|
82
|
+
|
83
|
+
### 4. 分页配置 (pagination)
|
84
|
+
|
85
|
+
```json
|
86
|
+
{
|
87
|
+
"pagination": {
|
88
|
+
"enabled": true,
|
89
|
+
"pageSize": 10
|
90
|
+
}
|
91
|
+
}
|
92
|
+
```
|
93
|
+
|
94
|
+
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|
95
|
+
|------|------|------|--------|------|
|
96
|
+
| enabled | boolean | 否 | false | 是否启用分页 |
|
97
|
+
| pageSize | number | 否 | 10 | 每页数据条数 |
|
98
|
+
|
99
|
+
### 5. 请求验证配置 (requestSchema)
|
100
|
+
|
101
|
+
```json
|
102
|
+
{
|
103
|
+
"requestSchema": {
|
104
|
+
"name": "string",
|
105
|
+
"age": "number",
|
106
|
+
"email": "string"
|
107
|
+
}
|
108
|
+
}
|
109
|
+
```
|
110
|
+
|
111
|
+
## Mock.js 模板使用说明
|
112
|
+
|
113
|
+
### 常用模板示例
|
114
|
+
|
115
|
+
- `@cname` - 生成中文姓名
|
116
|
+
- `@name` - 生成英文姓名
|
117
|
+
- `@email` - 生成邮箱地址
|
118
|
+
- `@datetime` - 生成日期时间
|
119
|
+
- `@image` - 生成图片链接
|
120
|
+
- `@city` - 生成城市名
|
121
|
+
- `@id` - 生成随机 ID
|
122
|
+
- `@guid` - 生成 GUID
|
123
|
+
- `@ctitle` - 生成中文标题
|
124
|
+
- `@cparagraph` - 生成中文段落
|
125
|
+
- `|+1` - 自增数字
|
126
|
+
|
127
|
+
## 完整配置示例
|
128
|
+
|
129
|
+
### 1. 用户管理接口
|
130
|
+
|
131
|
+
```json
|
132
|
+
{
|
133
|
+
"server": {
|
134
|
+
"port": 8080,
|
135
|
+
"baseProxy": "/api"
|
136
|
+
},
|
137
|
+
"routes": [
|
138
|
+
{
|
139
|
+
"path": "/users",
|
140
|
+
"methods": {
|
141
|
+
"get": {
|
142
|
+
"type": "array",
|
143
|
+
"mock": {
|
144
|
+
"enabled": true,
|
145
|
+
"total": 100,
|
146
|
+
"template": {
|
147
|
+
"id|+1": 1,
|
148
|
+
"name": "@cname",
|
149
|
+
"age|18-60": 1,
|
150
|
+
"email": "@email",
|
151
|
+
"address": "@city(true)"
|
152
|
+
}
|
153
|
+
},
|
154
|
+
"pagination": {
|
155
|
+
"enabled": true,
|
156
|
+
"pageSize": 10
|
157
|
+
}
|
158
|
+
},
|
159
|
+
"post": {
|
160
|
+
"requestSchema": {
|
161
|
+
"name": "string",
|
162
|
+
"age": "number",
|
163
|
+
"email": "string"
|
164
|
+
},
|
165
|
+
"response": {
|
166
|
+
"success": true,
|
167
|
+
"message": "创建成功"
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
]
|
173
|
+
}
|
174
|
+
```
|
175
|
+
|
176
|
+
### 2. 文章管理接口(带嵌套数据)
|
177
|
+
|
178
|
+
```json
|
179
|
+
{
|
180
|
+
"path": "/articles",
|
181
|
+
"methods": {
|
182
|
+
"get": {
|
183
|
+
"type": "array",
|
184
|
+
"mock": {
|
185
|
+
"enabled": true,
|
186
|
+
"total": 50,
|
187
|
+
"template": {
|
188
|
+
"id|+1": 1,
|
189
|
+
"title": "@ctitle",
|
190
|
+
"content": "@cparagraph",
|
191
|
+
"author": {
|
192
|
+
"id|+1": 100,
|
193
|
+
"name": "@cname",
|
194
|
+
"avatar": "@image('100x100')"
|
195
|
+
},
|
196
|
+
"comments|0-10": [{
|
197
|
+
"id|+1": 1,
|
198
|
+
"content": "@csentence",
|
199
|
+
"user": "@cname",
|
200
|
+
"createTime": "@datetime"
|
201
|
+
}]
|
202
|
+
}
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
```
|
208
|
+
|
209
|
+
## 使用技巧
|
210
|
+
|
211
|
+
### 1. 动态路由参数
|
212
|
+
```json
|
213
|
+
{
|
214
|
+
"path": "/users/:id/posts",
|
215
|
+
"methods": {
|
216
|
+
"get": {
|
217
|
+
"type": "array",
|
218
|
+
"mock": {
|
219
|
+
"enabled": true,
|
220
|
+
"total": 10,
|
221
|
+
"template": {
|
222
|
+
"id|+1": 1,
|
223
|
+
"title": "@ctitle",
|
224
|
+
"content": "@cparagraph"
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
}
|
229
|
+
}
|
230
|
+
```
|
231
|
+
|
232
|
+
### 2. 分页查询
|
233
|
+
```bash
|
234
|
+
# 获取第二页,每页10条数据
|
235
|
+
curl http://localhost:8080/api/users?page=2&pageSize=10
|
236
|
+
```
|
237
|
+
|
238
|
+
### 3. 数据范围生成
|
239
|
+
```json
|
240
|
+
{
|
241
|
+
"template": {
|
242
|
+
"age|18-60": 1, // 生成18-60之间的数字
|
243
|
+
"score|1-100.1": 1, // 生成1-100之间的浮点数,保留1位小数
|
244
|
+
"items|1-5": ["item"] // 生成1-5个重复项
|
245
|
+
}
|
246
|
+
}
|
247
|
+
```
|
248
|
+
|
249
|
+
## 注意事项
|
250
|
+
|
251
|
+
1. **路径参数**
|
252
|
+
- 动态路由参数使用 `:参数名` 格式
|
253
|
+
- 例如:`/users/:id/posts/:postId`
|
254
|
+
|
255
|
+
2. **Mock 数据**
|
256
|
+
- `enabled` 为 `true` 时才会生成 mock 数据
|
257
|
+
- `template` 中可以使用所有 Mock.js 支持的语法
|
258
|
+
|
259
|
+
3. **分页**
|
260
|
+
- 启用分页后,可通过 `?page=1&pageSize=10` 访问分页数据
|
261
|
+
- 响应头会包含 `X-Total-Count` 表示总数据量
|
262
|
+
|
263
|
+
4. **数据持久化**
|
264
|
+
- POST、PUT、DELETE 操作会自动保存到 data.json 文件
|
265
|
+
- 重启服务器后数据仍然保留
|
266
|
+
|
267
|
+
## 最佳实践
|
268
|
+
|
269
|
+
1. **合理使用 Mock 数据**
|
270
|
+
```json
|
271
|
+
{
|
272
|
+
"mock": {
|
273
|
+
"enabled": true,
|
274
|
+
"total": 100,
|
275
|
+
"template": {
|
276
|
+
// 使用自增ID避免重复
|
277
|
+
"id|+1": 1,
|
278
|
+
// 使用合适的数据类型
|
279
|
+
"age|18-60": 1
|
280
|
+
}
|
281
|
+
}
|
282
|
+
}
|
283
|
+
```
|
284
|
+
|
285
|
+
2. **适当的分页配置**
|
286
|
+
```json
|
287
|
+
{
|
288
|
+
"pagination": {
|
289
|
+
"enabled": true,
|
290
|
+
"pageSize": 10 // 根据数据量设置合适的页大小
|
291
|
+
}
|
292
|
+
}
|
293
|
+
```
|
294
|
+
|
295
|
+
3. **请求验证**
|
296
|
+
```json
|
297
|
+
{
|
298
|
+
"requestSchema": {
|
299
|
+
// 确保必要的字段都有类型验证
|
300
|
+
"name": "string",
|
301
|
+
"age": "number",
|
302
|
+
"email": "string"
|
303
|
+
}
|
304
|
+
}
|
305
|
+
```
|
package/CONFIG.md
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
# JSON API Mocker Configuration Guide
|
2
|
+
|
3
|
+
A comprehensive guide to help you understand and write the `data.json` configuration file.
|
4
|
+
|
5
|
+
## Configuration Structure
|
6
|
+
|
7
|
+
```json
|
8
|
+
{
|
9
|
+
"server": {
|
10
|
+
"port": 8080,
|
11
|
+
"baseProxy": "/api"
|
12
|
+
},
|
13
|
+
"routes": []
|
14
|
+
}
|
15
|
+
```
|
16
|
+
|
17
|
+
## Configuration Details
|
18
|
+
|
19
|
+
### 1. Server Configuration (server)
|
20
|
+
|
21
|
+
| Field | Type | Required | Default | Description |
|
22
|
+
|-------|------|----------|---------|-------------|
|
23
|
+
| port | number | No | 8080 | Server port number |
|
24
|
+
| baseProxy | string | No | "/api" | Base path for all APIs |
|
25
|
+
|
26
|
+
### 2. Routes Configuration (routes)
|
27
|
+
|
28
|
+
Routes is an array where each element is a route configuration object:
|
29
|
+
|
30
|
+
```json
|
31
|
+
{
|
32
|
+
"path": "/users",
|
33
|
+
"methods": {
|
34
|
+
"get": {},
|
35
|
+
"post": {},
|
36
|
+
"put": {},
|
37
|
+
"delete": {}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
```
|
41
|
+
|
42
|
+
#### 2.1 Route Basic Configuration
|
43
|
+
|
44
|
+
| Field | Type | Required | Description |
|
45
|
+
|-------|------|----------|-------------|
|
46
|
+
| path | string | Yes | Route path, supports parameters like `/users/:id` |
|
47
|
+
| methods | object | Yes | HTTP methods configuration object |
|
48
|
+
|
49
|
+
#### 2.2 Method Configuration (methods)
|
50
|
+
|
51
|
+
Each HTTP method can include the following configurations:
|
52
|
+
|
53
|
+
| Field | Type | Required | Description |
|
54
|
+
|-------|------|----------|-------------|
|
55
|
+
| type | string | No | Response type: "array" or "object" |
|
56
|
+
| response | any | No | Static response data |
|
57
|
+
| mock | object | No | Mock.js configuration |
|
58
|
+
| pagination | object | No | Pagination configuration |
|
59
|
+
| requestSchema | object | No | Request body validation schema |
|
60
|
+
|
61
|
+
### 3. Mock Data Configuration (mock)
|
62
|
+
|
63
|
+
```json
|
64
|
+
{
|
65
|
+
"mock": {
|
66
|
+
"enabled": true,
|
67
|
+
"total": 100,
|
68
|
+
"template": {
|
69
|
+
"id|+1": 1,
|
70
|
+
"name": "@name",
|
71
|
+
"email": "@email"
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
```
|
76
|
+
|
77
|
+
| Field | Type | Required | Description |
|
78
|
+
|-------|------|----------|-------------|
|
79
|
+
| enabled | boolean | Yes | Enable/disable mock data |
|
80
|
+
| total | number | Yes | Total number of records to generate |
|
81
|
+
| template | object | Yes | Mock.js data template |
|
82
|
+
|
83
|
+
### 4. Pagination Configuration (pagination)
|
84
|
+
|
85
|
+
```json
|
86
|
+
{
|
87
|
+
"pagination": {
|
88
|
+
"enabled": true,
|
89
|
+
"pageSize": 10
|
90
|
+
}
|
91
|
+
}
|
92
|
+
```
|
93
|
+
|
94
|
+
| Field | Type | Required | Default | Description |
|
95
|
+
|-------|------|----------|---------|-------------|
|
96
|
+
| enabled | boolean | No | false | Enable/disable pagination |
|
97
|
+
| pageSize | number | No | 10 | Number of items per page |
|
98
|
+
|
99
|
+
### 5. Request Validation Configuration (requestSchema)
|
100
|
+
|
101
|
+
```json
|
102
|
+
{
|
103
|
+
"requestSchema": {
|
104
|
+
"name": "string",
|
105
|
+
"age": "number",
|
106
|
+
"email": "string"
|
107
|
+
}
|
108
|
+
}
|
109
|
+
```
|
110
|
+
|
111
|
+
## Complete Configuration Examples
|
112
|
+
|
113
|
+
### 1. Basic User CRUD API
|
114
|
+
|
115
|
+
```json
|
116
|
+
{
|
117
|
+
"server": {
|
118
|
+
"port": 8080,
|
119
|
+
"baseProxy": "/api"
|
120
|
+
},
|
121
|
+
"routes": [
|
122
|
+
{
|
123
|
+
"path": "/users",
|
124
|
+
"methods": {
|
125
|
+
"get": {
|
126
|
+
"type": "array",
|
127
|
+
"mock": {
|
128
|
+
"enabled": true,
|
129
|
+
"total": 100,
|
130
|
+
"template": {
|
131
|
+
"id|+1": 1,
|
132
|
+
"name": "@name",
|
133
|
+
"age|18-60": 1,
|
134
|
+
"email": "@email",
|
135
|
+
"address": "@city"
|
136
|
+
}
|
137
|
+
},
|
138
|
+
"pagination": {
|
139
|
+
"enabled": true,
|
140
|
+
"pageSize": 10
|
141
|
+
}
|
142
|
+
},
|
143
|
+
"post": {
|
144
|
+
"requestSchema": {
|
145
|
+
"name": "string",
|
146
|
+
"age": "number",
|
147
|
+
"email": "string"
|
148
|
+
},
|
149
|
+
"response": {
|
150
|
+
"success": true,
|
151
|
+
"message": "Created successfully"
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
]
|
157
|
+
}
|
158
|
+
```
|
159
|
+
|
160
|
+
### 2. Articles API with Nested Data
|
161
|
+
|
162
|
+
```json
|
163
|
+
{
|
164
|
+
"path": "/articles",
|
165
|
+
"methods": {
|
166
|
+
"get": {
|
167
|
+
"type": "array",
|
168
|
+
"mock": {
|
169
|
+
"enabled": true,
|
170
|
+
"total": 50,
|
171
|
+
"template": {
|
172
|
+
"id|+1": 1,
|
173
|
+
"title": "@title",
|
174
|
+
"content": "@paragraph",
|
175
|
+
"author": {
|
176
|
+
"id|+1": 100,
|
177
|
+
"name": "@name",
|
178
|
+
"avatar": "@image('100x100')"
|
179
|
+
},
|
180
|
+
"comments|0-10": [{
|
181
|
+
"id|+1": 1,
|
182
|
+
"content": "@sentence",
|
183
|
+
"user": "@name",
|
184
|
+
"createTime": "@datetime"
|
185
|
+
}]
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
```
|
192
|
+
|
193
|
+
### 3. Dynamic Route Parameters Example
|
194
|
+
|
195
|
+
```json
|
196
|
+
{
|
197
|
+
"path": "/users/:id/posts",
|
198
|
+
"methods": {
|
199
|
+
"get": {
|
200
|
+
"type": "array",
|
201
|
+
"mock": {
|
202
|
+
"enabled": true,
|
203
|
+
"total": 10,
|
204
|
+
"template": {
|
205
|
+
"id|+1": 1,
|
206
|
+
"title": "@title",
|
207
|
+
"content": "@paragraph"
|
208
|
+
}
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
```
|
214
|
+
|
215
|
+
## Important Notes
|
216
|
+
|
217
|
+
1. **Route Parameters**
|
218
|
+
- Dynamic route parameters use `:paramName` format
|
219
|
+
- Example: `/users/:id/posts/:postId`
|
220
|
+
|
221
|
+
2. **Mock Data**
|
222
|
+
- Mock data generation only works when `enabled` is `true`
|
223
|
+
- `template` supports all Mock.js syntax
|
224
|
+
|
225
|
+
3. **Pagination**
|
226
|
+
- When enabled, use `?page=1&pageSize=10` to access paginated data
|
227
|
+
- Response headers include `X-Total-Count` for total count
|
228
|
+
|
229
|
+
4. **Data Persistence**
|
230
|
+
- POST, PUT, DELETE operations automatically save to data.json
|
231
|
+
- Data persists after server restart
|
232
|
+
|
233
|
+
## Best Practices
|
234
|
+
|
235
|
+
1. **Effective Use of Mock Data**
|
236
|
+
```json
|
237
|
+
{
|
238
|
+
"mock": {
|
239
|
+
"enabled": true,
|
240
|
+
"total": 100,
|
241
|
+
"template": {
|
242
|
+
// Use auto-increment for IDs
|
243
|
+
"id|+1": 1,
|
244
|
+
// Use appropriate data types
|
245
|
+
"age|18-60": 1
|
246
|
+
}
|
247
|
+
}
|
248
|
+
}
|
249
|
+
```
|
250
|
+
|
251
|
+
2. **Proper Pagination Settings**
|
252
|
+
```json
|
253
|
+
{
|
254
|
+
"pagination": {
|
255
|
+
"enabled": true,
|
256
|
+
"pageSize": 10 // Set appropriate page size based on data volume
|
257
|
+
}
|
258
|
+
}
|
259
|
+
```
|
260
|
+
|
261
|
+
3. **Request Validation**
|
262
|
+
```json
|
263
|
+
{
|
264
|
+
"requestSchema": {
|
265
|
+
// Ensure all required fields have type validation
|
266
|
+
"name": "string",
|
267
|
+
"age": "number",
|
268
|
+
"email": "string"
|
269
|
+
}
|
270
|
+
}
|
271
|
+
```
|
package/README.ch.md
CHANGED
@@ -3,11 +3,12 @@
|
|
3
3
|
一个轻量级且灵活的 Mock 服务器,通过 JSON 配置快速创建 RESTful API。
|
4
4
|
|
5
5
|
<p align="center">
|
6
|
-
<img src="https://img.shields.io/npm/v/json-
|
7
|
-
<img src="https://img.shields.io/npm/l/json-
|
8
|
-
<img src="https://img.shields.io/npm/dt/json-
|
6
|
+
<img src="https://img.shields.io/npm/v/json-api-mocker" alt="npm version" />
|
7
|
+
<img src="https://img.shields.io/npm/l/json-api-mocker" alt="license" />
|
8
|
+
<img src="https://img.shields.io/npm/dt/json-api-mocker" alt="downloads" />
|
9
9
|
</p>
|
10
10
|
|
11
|
+
|
11
12
|
## ✨ 特性
|
12
13
|
|
13
14
|
- 🚀 通过 JSON 配置快速搭建
|
@@ -15,6 +16,7 @@
|
|
15
16
|
- 📝 自动数据持久化
|
16
17
|
- 🔍 内置分页支持
|
17
18
|
- 🛠 可自定义响应结构
|
19
|
+
- 💡 集成 Mock.js 实现强大的数据模拟
|
18
20
|
- 💡 TypeScript 支持
|
19
21
|
|
20
22
|
## 📦 安装
|
@@ -152,6 +154,105 @@ Mock 服务器已启动:
|
|
152
154
|
}
|
153
155
|
```
|
154
156
|
|
157
|
+
### Mock.js 集成
|
158
|
+
|
159
|
+
你可以使用 Mock.js 模板来生成动态数据:
|
160
|
+
|
161
|
+
```json
|
162
|
+
{
|
163
|
+
"path": "/users",
|
164
|
+
"methods": {
|
165
|
+
"get": {
|
166
|
+
"type": "array",
|
167
|
+
"mock": {
|
168
|
+
"enabled": true,
|
169
|
+
"total": 200,
|
170
|
+
"template": {
|
171
|
+
"id|+1": 1,
|
172
|
+
"name": "@cname",
|
173
|
+
"email": "@email",
|
174
|
+
"age|18-60": 1,
|
175
|
+
"address": "@city(true)",
|
176
|
+
"avatar": "@image('200x200')",
|
177
|
+
"createTime": "@datetime"
|
178
|
+
}
|
179
|
+
},
|
180
|
+
"pagination": {
|
181
|
+
"enabled": true,
|
182
|
+
"pageSize": 10
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
186
|
+
}
|
187
|
+
```
|
188
|
+
|
189
|
+
#### 可用的 Mock.js 模板
|
190
|
+
|
191
|
+
- `@cname` - 生成中文姓名
|
192
|
+
- `@name` - 生成英文姓名
|
193
|
+
- `@email` - 生成邮箱地址
|
194
|
+
- `@datetime` - 生成日期时间
|
195
|
+
- `@image` - 生成图片链接
|
196
|
+
- `@city` - 生成城市名
|
197
|
+
- `@id` - 生成随机 ID
|
198
|
+
- `@guid` - 生成 GUID
|
199
|
+
- `@title` - 生成标题
|
200
|
+
- `@paragraph` - 生成段落
|
201
|
+
- `|+1` - 自增数字
|
202
|
+
|
203
|
+
更多 Mock.js 模板请访问 [Mock.js 文档](http://mockjs.com/examples.html)
|
204
|
+
|
205
|
+
#### Mock.js 使用示例
|
206
|
+
|
207
|
+
1. 生成用户列表:
|
208
|
+
```json
|
209
|
+
{
|
210
|
+
"mock": {
|
211
|
+
"enabled": true,
|
212
|
+
"total": 100,
|
213
|
+
"template": {
|
214
|
+
"id|+1": 1,
|
215
|
+
"name": "@cname",
|
216
|
+
"email": "@email"
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
```
|
221
|
+
|
222
|
+
2. 生成文章列表:
|
223
|
+
```json
|
224
|
+
{
|
225
|
+
"mock": {
|
226
|
+
"enabled": true,
|
227
|
+
"total": 50,
|
228
|
+
"template": {
|
229
|
+
"id|+1": 1,
|
230
|
+
"title": "@ctitle",
|
231
|
+
"content": "@cparagraph",
|
232
|
+
"author": "@cname",
|
233
|
+
"publishDate": "@datetime"
|
234
|
+
}
|
235
|
+
}
|
236
|
+
}
|
237
|
+
```
|
238
|
+
|
239
|
+
3. 生成商品列表:
|
240
|
+
```json
|
241
|
+
{
|
242
|
+
"mock": {
|
243
|
+
"enabled": true,
|
244
|
+
"total": 30,
|
245
|
+
"template": {
|
246
|
+
"id|+1": 1,
|
247
|
+
"name": "@ctitle(3, 5)",
|
248
|
+
"price|100-1000.2": 1,
|
249
|
+
"category": "@pick(['电子产品', '图书', '服装'])",
|
250
|
+
"image": "@image('200x200', '#50B347', '#FFF', 'Mock.js')"
|
251
|
+
}
|
252
|
+
}
|
253
|
+
}
|
254
|
+
```
|
255
|
+
|
155
256
|
## 🎯 API 示例
|
156
257
|
|
157
258
|
### 基本的 CRUD 操作
|
package/README.md
CHANGED
@@ -15,6 +15,7 @@ A lightweight and flexible mock server that uses JSON configuration to quickly c
|
|
15
15
|
- 📝 Automatic data persistence
|
16
16
|
- 🔍 Built-in pagination support
|
17
17
|
- 🛠 Customizable response schemas
|
18
|
+
- 💡 Integration with Mock.js for powerful data mocking
|
18
19
|
- 💡 TypeScript support
|
19
20
|
|
20
21
|
## 📦 Installation
|
@@ -152,6 +153,104 @@ Each route can support multiple HTTP methods:
|
|
152
153
|
}
|
153
154
|
```
|
154
155
|
|
156
|
+
### Mock.js Integration
|
157
|
+
|
158
|
+
You can use Mock.js templates to generate dynamic data:
|
159
|
+
|
160
|
+
```json
|
161
|
+
{
|
162
|
+
"path": "/users",
|
163
|
+
"methods": {
|
164
|
+
"get": {
|
165
|
+
"type": "array",
|
166
|
+
"mock": {
|
167
|
+
"enabled": true,
|
168
|
+
"total": 200,
|
169
|
+
"template": {
|
170
|
+
"id|+1": 1,
|
171
|
+
"name": "@name",
|
172
|
+
"email": "@email",
|
173
|
+
"age|18-60": 1,
|
174
|
+
"address": "@city(true)",
|
175
|
+
"avatar": "@image('200x200')",
|
176
|
+
"createTime": "@datetime"
|
177
|
+
}
|
178
|
+
},
|
179
|
+
"pagination": {
|
180
|
+
"enabled": true,
|
181
|
+
"pageSize": 10
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
186
|
+
```
|
187
|
+
|
188
|
+
#### Available Mock.js Templates
|
189
|
+
|
190
|
+
- `@name` - Generate random name
|
191
|
+
- `@email` - Generate random email
|
192
|
+
- `@datetime` - Generate random datetime
|
193
|
+
- `@image` - Generate random image URL
|
194
|
+
- `@city` - Generate random city name
|
195
|
+
- `@id` - Generate random ID
|
196
|
+
- `@guid` - Generate GUID
|
197
|
+
- `@title` - Generate random title
|
198
|
+
- `@paragraph` - Generate random paragraph
|
199
|
+
- `|+1` - Auto increment number
|
200
|
+
|
201
|
+
For more Mock.js templates, visit [Mock.js Documentation](http://mockjs.com/examples.html)
|
202
|
+
|
203
|
+
#### Examples with Mock.js
|
204
|
+
|
205
|
+
1. Generate user list with random data:
|
206
|
+
```json
|
207
|
+
{
|
208
|
+
"mock": {
|
209
|
+
"enabled": true,
|
210
|
+
"total": 100,
|
211
|
+
"template": {
|
212
|
+
"id|+1": 1,
|
213
|
+
"name": "@name",
|
214
|
+
"email": "@email"
|
215
|
+
}
|
216
|
+
}
|
217
|
+
}
|
218
|
+
```
|
219
|
+
|
220
|
+
2. Generate article list with random content:
|
221
|
+
```json
|
222
|
+
{
|
223
|
+
"mock": {
|
224
|
+
"enabled": true,
|
225
|
+
"total": 50,
|
226
|
+
"template": {
|
227
|
+
"id|+1": 1,
|
228
|
+
"title": "@title",
|
229
|
+
"content": "@paragraph",
|
230
|
+
"author": "@name",
|
231
|
+
"publishDate": "@datetime"
|
232
|
+
}
|
233
|
+
}
|
234
|
+
}
|
235
|
+
```
|
236
|
+
|
237
|
+
3. Generate product list with random prices:
|
238
|
+
```json
|
239
|
+
{
|
240
|
+
"mock": {
|
241
|
+
"enabled": true,
|
242
|
+
"total": 30,
|
243
|
+
"template": {
|
244
|
+
"id|+1": 1,
|
245
|
+
"name": "@title(3, 5)",
|
246
|
+
"price|100-1000.2": 1,
|
247
|
+
"category": "@pick(['Electronics', 'Books', 'Clothing'])",
|
248
|
+
"image": "@image('200x200', '#50B347', '#FFF', 'Mock.js')"
|
249
|
+
}
|
250
|
+
}
|
251
|
+
}
|
252
|
+
```
|
253
|
+
|
155
254
|
## 🎯 API Examples
|
156
255
|
|
157
256
|
### Basic CRUD Operations
|
package/dist/server.d.ts
CHANGED
@@ -5,14 +5,9 @@ export declare class MockServer {
|
|
5
5
|
private configPath;
|
6
6
|
constructor(config: Config, configPath?: string);
|
7
7
|
private setupMiddleware;
|
8
|
+
private generateMockData;
|
9
|
+
private handleRequest;
|
8
10
|
private setupRoutes;
|
9
|
-
private saveConfig;
|
10
|
-
private findUserById;
|
11
|
-
private getNextUserId;
|
12
11
|
private createRoute;
|
13
|
-
private handleRequest;
|
14
|
-
private handlePostRequest;
|
15
|
-
private handlePutRequest;
|
16
|
-
private handleDeleteRequest;
|
17
12
|
start(): void;
|
18
13
|
}
|
package/dist/server.js
CHANGED
@@ -4,15 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.MockServer = void 0;
|
7
|
+
const mockjs_1 = __importDefault(require("mockjs"));
|
7
8
|
const express_1 = __importDefault(require("express"));
|
8
9
|
const cors_1 = __importDefault(require("cors"));
|
9
|
-
const fs_1 = __importDefault(require("fs"));
|
10
|
-
const path_1 = __importDefault(require("path"));
|
11
10
|
class MockServer {
|
12
11
|
constructor(config, configPath = 'data.json') {
|
13
12
|
this.app = (0, express_1.default)();
|
14
13
|
this.config = config;
|
15
|
-
this.configPath =
|
14
|
+
this.configPath = configPath;
|
16
15
|
this.setupMiddleware();
|
17
16
|
this.setupRoutes();
|
18
17
|
}
|
@@ -20,6 +19,43 @@ class MockServer {
|
|
20
19
|
this.app.use((0, cors_1.default)());
|
21
20
|
this.app.use(express_1.default.json());
|
22
21
|
}
|
22
|
+
generateMockData(config) {
|
23
|
+
try {
|
24
|
+
if (config.mock?.enabled && config.mock.template) {
|
25
|
+
const { total, template } = config.mock;
|
26
|
+
return mockjs_1.default.mock({
|
27
|
+
[`data|${total}`]: [template]
|
28
|
+
}).data;
|
29
|
+
}
|
30
|
+
return config.response;
|
31
|
+
}
|
32
|
+
catch (error) {
|
33
|
+
console.error('生成 Mock 数据时出错:', error);
|
34
|
+
return config.response;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
handleRequest(config) {
|
38
|
+
return (req, res) => {
|
39
|
+
try {
|
40
|
+
console.log(`收到请求: ${req.method} ${req.url}`);
|
41
|
+
let responseData = this.generateMockData(config);
|
42
|
+
if (config.pagination?.enabled && Array.isArray(responseData)) {
|
43
|
+
const page = parseInt(req.query.page) || 1;
|
44
|
+
const pageSize = parseInt(req.query.pageSize) || config.pagination.pageSize;
|
45
|
+
const startIndex = (page - 1) * pageSize;
|
46
|
+
const endIndex = startIndex + pageSize;
|
47
|
+
const paginatedData = responseData.slice(startIndex, endIndex);
|
48
|
+
res.header('X-Total-Count', responseData.length.toString());
|
49
|
+
responseData = paginatedData;
|
50
|
+
}
|
51
|
+
res.json(responseData);
|
52
|
+
}
|
53
|
+
catch (error) {
|
54
|
+
console.error('处理请求时出错:', error);
|
55
|
+
res.status(500).json({ error: '服务器内部错误' });
|
56
|
+
}
|
57
|
+
};
|
58
|
+
}
|
23
59
|
setupRoutes() {
|
24
60
|
this.config.routes.forEach((route) => {
|
25
61
|
Object.entries(route.methods).forEach(([method, methodConfig]) => {
|
@@ -27,28 +63,6 @@ class MockServer {
|
|
27
63
|
});
|
28
64
|
});
|
29
65
|
}
|
30
|
-
saveConfig() {
|
31
|
-
fs_1.default.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), 'utf-8');
|
32
|
-
}
|
33
|
-
findUserById(id) {
|
34
|
-
const usersRoute = this.config.routes.find(route => route.path === '/users');
|
35
|
-
if (!usersRoute)
|
36
|
-
return null;
|
37
|
-
const getMethod = usersRoute.methods.get;
|
38
|
-
if (!getMethod || !Array.isArray(getMethod.response))
|
39
|
-
return null;
|
40
|
-
return getMethod.response.find(user => user.id === id);
|
41
|
-
}
|
42
|
-
getNextUserId() {
|
43
|
-
const usersRoute = this.config.routes.find(route => route.path === '/users');
|
44
|
-
if (!usersRoute)
|
45
|
-
return 1;
|
46
|
-
const getMethod = usersRoute.methods.get;
|
47
|
-
if (!getMethod || !Array.isArray(getMethod.response))
|
48
|
-
return 1;
|
49
|
-
const maxId = Math.max(...getMethod.response.map(user => user.id));
|
50
|
-
return maxId + 1;
|
51
|
-
}
|
52
66
|
createRoute(path, method, config) {
|
53
67
|
const fullPath = `${this.config.server.baseProxy}${path}`;
|
54
68
|
console.log(`创建路由: ${method.toUpperCase()} ${fullPath}`);
|
@@ -57,87 +71,16 @@ class MockServer {
|
|
57
71
|
this.app.get(fullPath, this.handleRequest(config));
|
58
72
|
break;
|
59
73
|
case 'post':
|
60
|
-
this.app.post(fullPath, this.
|
74
|
+
this.app.post(fullPath, this.handleRequest(config));
|
61
75
|
break;
|
62
76
|
case 'put':
|
63
|
-
this.app.put(`${fullPath}/:id`, this.
|
77
|
+
this.app.put(`${fullPath}/:id`, this.handleRequest(config));
|
64
78
|
break;
|
65
79
|
case 'delete':
|
66
|
-
this.app.delete(`${fullPath}/:id`, this.
|
80
|
+
this.app.delete(`${fullPath}/:id`, this.handleRequest(config));
|
67
81
|
break;
|
68
82
|
}
|
69
83
|
}
|
70
|
-
handleRequest(config) {
|
71
|
-
return (req, res) => {
|
72
|
-
console.log(`收到请求: ${req.method} ${req.url}`);
|
73
|
-
if (config.pagination?.enabled && config.type === 'array') {
|
74
|
-
const page = parseInt(req.query.page) || 1;
|
75
|
-
const pageSize = parseInt(req.query.pageSize) || config.pagination.pageSize;
|
76
|
-
const startIndex = (page - 1) * pageSize;
|
77
|
-
const endIndex = startIndex + pageSize;
|
78
|
-
const data = config.response.slice(startIndex, endIndex);
|
79
|
-
res.header('X-Total-Count', config.pagination.totalCount.toString());
|
80
|
-
res.json(data);
|
81
|
-
}
|
82
|
-
else {
|
83
|
-
res.json(config.response);
|
84
|
-
}
|
85
|
-
};
|
86
|
-
}
|
87
|
-
handlePostRequest(config) {
|
88
|
-
return (req, res) => {
|
89
|
-
console.log(`收到创建请求: ${req.url}`, req.body);
|
90
|
-
const usersRoute = this.config.routes.find(route => route.path === '/users');
|
91
|
-
if (!usersRoute) {
|
92
|
-
return res.status(404).json({ error: '路由未找到' });
|
93
|
-
}
|
94
|
-
const getMethod = usersRoute.methods.get;
|
95
|
-
if (!getMethod || !Array.isArray(getMethod.response)) {
|
96
|
-
return res.status(500).json({ error: '数据格式错误' });
|
97
|
-
}
|
98
|
-
const newUser = {
|
99
|
-
id: this.getNextUserId(),
|
100
|
-
...req.body
|
101
|
-
};
|
102
|
-
getMethod.response.push(newUser);
|
103
|
-
this.saveConfig();
|
104
|
-
res.status(201).json(newUser);
|
105
|
-
};
|
106
|
-
}
|
107
|
-
handlePutRequest(config) {
|
108
|
-
return (req, res) => {
|
109
|
-
const userId = parseInt(req.params.id);
|
110
|
-
console.log(`收到更新请求: ${req.url}`, req.body);
|
111
|
-
const user = this.findUserById(userId);
|
112
|
-
if (!user) {
|
113
|
-
return res.status(404).json({ error: '用户未找到' });
|
114
|
-
}
|
115
|
-
Object.assign(user, req.body);
|
116
|
-
this.saveConfig();
|
117
|
-
res.json(user);
|
118
|
-
};
|
119
|
-
}
|
120
|
-
handleDeleteRequest(config) {
|
121
|
-
return (req, res) => {
|
122
|
-
const userId = parseInt(req.params.id);
|
123
|
-
console.log(`收到删除请求: ${req.url}`);
|
124
|
-
const usersRoute = this.config.routes.find(route => route.path === '/users');
|
125
|
-
if (!usersRoute) {
|
126
|
-
return res.status(404).json({ error: '路由未找到' });
|
127
|
-
}
|
128
|
-
const getMethod = usersRoute.methods.get;
|
129
|
-
if (!getMethod || !Array.isArray(getMethod.response)) {
|
130
|
-
return res.status(500).json({ error: '数据格式错误' });
|
131
|
-
}
|
132
|
-
const userIndex = getMethod.response.findIndex(user => user.id === userId);
|
133
|
-
if (userIndex === -1) {
|
134
|
-
return res.status(404).json({ error: '用户未找到' });
|
135
|
-
}
|
136
|
-
getMethod.response.splice(userIndex, 1);
|
137
|
-
this.saveConfig();
|
138
|
-
res.json({ success: true, message: '删除成功' });
|
139
|
-
};
|
140
|
-
}
|
141
84
|
start() {
|
142
85
|
this.app.listen(this.config.server.port, () => {
|
143
86
|
console.log(`Mock 服务器已启动:`);
|
package/dist/types.d.ts
CHANGED
@@ -7,12 +7,17 @@ export interface PaginationConfig {
|
|
7
7
|
pageSize: number;
|
8
8
|
totalCount: number;
|
9
9
|
}
|
10
|
+
export interface MockConfig {
|
11
|
+
enabled: boolean;
|
12
|
+
total: number;
|
13
|
+
template: Record<string, any>;
|
14
|
+
}
|
10
15
|
export interface MethodConfig {
|
11
16
|
type?: 'array' | 'object';
|
17
|
+
response?: any;
|
18
|
+
mock?: MockConfig;
|
12
19
|
pagination?: PaginationConfig;
|
13
|
-
response: any;
|
14
20
|
requestSchema?: Record<string, string>;
|
15
|
-
params?: string[];
|
16
21
|
}
|
17
22
|
export interface RouteConfig {
|
18
23
|
path: string;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "json-api-mocker",
|
3
|
-
"version": "1.0
|
3
|
+
"version": "1.2.0",
|
4
4
|
"description": "一个基于 JSON 配置的 Mock 服务器",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"types": "dist/index.d.ts",
|
@@ -10,7 +10,9 @@
|
|
10
10
|
"files": [
|
11
11
|
"dist",
|
12
12
|
"README.md",
|
13
|
-
"README.ch.md"
|
13
|
+
"README.ch.md",
|
14
|
+
"CONFIG.md",
|
15
|
+
"CONFIG.ch.md"
|
14
16
|
],
|
15
17
|
"scripts": {
|
16
18
|
"dev": "nodemon",
|
@@ -41,12 +43,14 @@
|
|
41
43
|
"homepage": "https://github.com/Selteve/json-api-mocker#readme",
|
42
44
|
"dependencies": {
|
43
45
|
"cors": "^2.8.5",
|
44
|
-
"express": "^4.17.1"
|
46
|
+
"express": "^4.17.1",
|
47
|
+
"mockjs": "^1.1.0"
|
45
48
|
},
|
46
49
|
"devDependencies": {
|
47
50
|
"@types/cors": "^2.8.13",
|
48
51
|
"@types/express": "^4.17.13",
|
49
52
|
"@types/jest": "^27.5.2",
|
53
|
+
"@types/mockjs": "^1.0.10",
|
50
54
|
"@types/node": "^16.18.0",
|
51
55
|
"jest": "^27.5.1",
|
52
56
|
"nodemon": "^2.0.22",
|