json-api-mocker 1.0.3 → 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.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-mock-server" alt="npm 版本" />
7
- <img src="https://img.shields.io/npm/l/json-mock-server" alt="许可证" />
8
- <img src="https://img.shields.io/npm/dt/json-mock-server" alt="下载量" />
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 = path_1.default.resolve(process.cwd(), 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.handlePostRequest(config));
74
+ this.app.post(fullPath, this.handleRequest(config));
61
75
  break;
62
76
  case 'put':
63
- this.app.put(`${fullPath}/:id`, this.handlePutRequest(config));
77
+ this.app.put(`${fullPath}/:id`, this.handleRequest(config));
64
78
  break;
65
79
  case 'delete':
66
- this.app.delete(`${fullPath}/:id`, this.handleDeleteRequest(config));
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,10 +7,16 @@ 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';
12
17
  pagination?: PaginationConfig;
13
- response: any;
18
+ mock?: MockConfig;
19
+ response?: any;
14
20
  requestSchema?: Record<string, string>;
15
21
  params?: string[];
16
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-api-mocker",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "一个基于 JSON 配置的 Mock 服务器",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -41,12 +41,14 @@
41
41
  "homepage": "https://github.com/Selteve/json-api-mocker#readme",
42
42
  "dependencies": {
43
43
  "cors": "^2.8.5",
44
- "express": "^4.17.1"
44
+ "express": "^4.17.1",
45
+ "mockjs": "^1.1.0"
45
46
  },
46
47
  "devDependencies": {
47
48
  "@types/cors": "^2.8.13",
48
49
  "@types/express": "^4.17.13",
49
50
  "@types/jest": "^27.5.2",
51
+ "@types/mockjs": "^1.0.10",
50
52
  "@types/node": "^16.18.0",
51
53
  "jest": "^27.5.1",
52
54
  "nodemon": "^2.0.22",