json-api-mocker 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.ch.md ADDED
@@ -0,0 +1,216 @@
1
+ # JSON Mock Server
2
+
3
+ 一个轻量级且灵活的 Mock 服务器,通过 JSON 配置快速创建 RESTful API。
4
+
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="下载量" />
9
+ </p>
10
+
11
+ ## ✨ 特性
12
+
13
+ - 🚀 通过 JSON 配置快速搭建
14
+ - 🔄 支持 GET、POST、PUT、DELETE 方法
15
+ - 📝 自动数据持久化
16
+ - 🔍 内置分页支持
17
+ - 🛠 可自定义响应结构
18
+ - 💡 TypeScript 支持
19
+
20
+ ## 📦 安装
21
+
22
+ ```bash
23
+ # 使用 npm
24
+ npm install json-mock-server
25
+
26
+ # 使用 yarn
27
+ yarn add json-mock-server
28
+
29
+ # 使用 pnpm
30
+ pnpm add json-mock-server
31
+ ```
32
+
33
+ ## 🚀 快速开始
34
+
35
+ ### 1. 创建配置文件
36
+
37
+ 在项目根目录创建 `data.json` 文件:
38
+
39
+ ```json
40
+ {
41
+ "server": {
42
+ "port": 8080,
43
+ "baseProxy": "/api"
44
+ },
45
+ "routes": [
46
+ {
47
+ "path": "/users",
48
+ "methods": {
49
+ "get": {
50
+ "type": "array",
51
+ "pagination": {
52
+ "enabled": true,
53
+ "pageSize": 10,
54
+ "totalCount": 100
55
+ },
56
+ "response": [
57
+ {
58
+ "id": 1,
59
+ "name": "张三",
60
+ "age": 30,
61
+ "city": "北京"
62
+ }
63
+ ]
64
+ }
65
+ }
66
+ }
67
+ ]
68
+ }
69
+ ```
70
+
71
+ ### 2. 启动服务器
72
+
73
+ ```bash
74
+ npx json-mock-server
75
+ ```
76
+
77
+ 现在你的 Mock 服务器已经在 `http://localhost:8080` 运行了!
78
+
79
+ ## 📖 配置指南
80
+
81
+ ### 服务器配置
82
+
83
+ `server` 部分配置基本的服务器设置:
84
+
85
+ ```json
86
+ {
87
+ "server": {
88
+ "port": 8080, // 服务器端口号
89
+ "baseProxy": "/api" // 所有路由的基础路径
90
+ }
91
+ }
92
+ ```
93
+
94
+ ### 路由配置
95
+
96
+ 每个路由可以支持多个 HTTP 方法:
97
+
98
+ ```json
99
+ {
100
+ "path": "/users", // 路由路径
101
+ "methods": {
102
+ "get": {
103
+ "type": "array", // 响应类型:array 或 object
104
+ "pagination": { // 可选的分页设置
105
+ "enabled": true,
106
+ "pageSize": 10,
107
+ "totalCount": 100
108
+ },
109
+ "response": [] // 响应数据
110
+ },
111
+ "post": {
112
+ "requestSchema": { // 请求体验证模式
113
+ "name": "string",
114
+ "age": "number"
115
+ },
116
+ "response": {
117
+ "success": true
118
+ }
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ ## 🎯 API 示例
125
+
126
+ ### 基本的 CRUD 操作
127
+
128
+ #### 获取用户列表
129
+ ```bash
130
+ curl http://localhost:8080/api/users
131
+ ```
132
+
133
+ #### 获取单个用户
134
+ ```bash
135
+ curl http://localhost:8080/api/users/1
136
+ ```
137
+
138
+ #### 创建用户
139
+ ```bash
140
+ curl -X POST http://localhost:8080/api/users \
141
+ -H "Content-Type: application/json" \
142
+ -d '{"name":"李四","age":25,"city":"上海"}'
143
+ ```
144
+
145
+ #### 更新用户
146
+ ```bash
147
+ curl -X PUT http://localhost:8080/api/users/1 \
148
+ -H "Content-Type: application/json" \
149
+ -d '{"name":"李四","age":26,"city":"上海"}'
150
+ ```
151
+
152
+ #### 删除用户
153
+ ```bash
154
+ curl -X DELETE http://localhost:8080/api/users/1
155
+ ```
156
+
157
+ ### 高级用法
158
+
159
+ #### 分页
160
+ ```bash
161
+ # 获取第2页,每页10条数据
162
+ curl http://localhost:8080/api/users?page=2&pageSize=10
163
+ ```
164
+
165
+ #### 自定义响应头
166
+ 服务器自动添加以下响应头:
167
+ - `X-Total-Count`:数据总条数(用于分页响应)
168
+
169
+ ## 🔧 高级配置
170
+
171
+ ### 动态路由
172
+
173
+ 你可以在路由中使用 URL 参数:
174
+
175
+ ```json
176
+ {
177
+ "path": "/users/:id/posts",
178
+ "methods": {
179
+ "get": {
180
+ "type": "array",
181
+ "response": []
182
+ }
183
+ }
184
+ }
185
+ ```
186
+
187
+ ### 请求验证
188
+
189
+ 为 POST/PUT 请求添加模式验证:
190
+
191
+ ```json
192
+ {
193
+ "requestSchema": {
194
+ "name": "string",
195
+ "age": "number",
196
+ "email": "string"
197
+ }
198
+ }
199
+ ```
200
+
201
+ ## 🤝 贡献指南
202
+
203
+ 1. Fork 本仓库
204
+ 2. 创建你的特性分支 (`git checkout -b feature/amazing-feature`)
205
+ 3. 提交你的改动 (`git commit -m '添加一些很棒的特性'`)
206
+ 4. 推送到分支 (`git push origin feature/amazing-feature`)
207
+ 5. 开启一个 Pull Request
208
+
209
+ ## 📄 许可证
210
+
211
+ MIT © [熊海印]
212
+
213
+ ## 🙏 致谢
214
+
215
+ - 感谢 Express.js 提供出色的 Web 框架
216
+ - 感谢所有贡献者和用户
package/README.md ADDED
@@ -0,0 +1,216 @@
1
+ # JSON Mock Server
2
+
3
+ A lightweight and flexible mock server that uses JSON configuration to quickly create RESTful APIs.
4
+
5
+ <p align="center">
6
+ <img src="https://img.shields.io/npm/v/json-mock-server" alt="npm version" />
7
+ <img src="https://img.shields.io/npm/l/json-mock-server" alt="license" />
8
+ <img src="https://img.shields.io/npm/dt/json-mock-server" alt="downloads" />
9
+ </p>
10
+
11
+ ## ✨ Features
12
+
13
+ - 🚀 Quick setup with JSON configuration
14
+ - 🔄 Support for GET, POST, PUT, DELETE methods
15
+ - 📝 Automatic data persistence
16
+ - 🔍 Built-in pagination support
17
+ - 🛠 Customizable response schemas
18
+ - 💡 TypeScript support
19
+
20
+ ## 📦 Installation
21
+
22
+ ```bash
23
+ # 使用 npm
24
+ npm install json-mock-server
25
+
26
+ # 使用 yarn
27
+ yarn add json-mock-server
28
+
29
+ # 使用 pnpm
30
+ pnpm add json-mock-server
31
+ ```
32
+
33
+ ## 🚀 Quick Start
34
+
35
+ ### 1. Create Configuration File
36
+
37
+ Create a `data.json` file in your project root:
38
+
39
+ ```json
40
+ {
41
+ "server": {
42
+ "port": 8080,
43
+ "baseProxy": "/api"
44
+ },
45
+ "routes": [
46
+ {
47
+ "path": "/users",
48
+ "methods": {
49
+ "get": {
50
+ "type": "array",
51
+ "pagination": {
52
+ "enabled": true,
53
+ "pageSize": 10,
54
+ "totalCount": 100
55
+ },
56
+ "response": [
57
+ {
58
+ "id": 1,
59
+ "name": "John",
60
+ "age": 30,
61
+ "city": "New York"
62
+ }
63
+ ]
64
+ }
65
+ }
66
+ }
67
+ ]
68
+ }
69
+ ```
70
+
71
+ ### 2. Start the Server
72
+
73
+ ```bash
74
+ npx json-mock-server
75
+ ```
76
+
77
+ Now your mock server is running at `http://localhost:8080`!
78
+
79
+ ## 📖 Configuration Guide
80
+
81
+ ### Server Configuration
82
+
83
+ The `server` section configures basic server settings:
84
+
85
+ ```json
86
+ {
87
+ "server": {
88
+ "port": 8080, // Server port number
89
+ "baseProxy": "/api" // Base path for all routes
90
+ }
91
+ }
92
+ ```
93
+
94
+ ### Route Configuration
95
+
96
+ Each route can support multiple HTTP methods:
97
+
98
+ ```json
99
+ {
100
+ "path": "/users", // Route path
101
+ "methods": {
102
+ "get": {
103
+ "type": "array", // Response type: "array" or "object"
104
+ "pagination": { // Optional pagination settings
105
+ "enabled": true,
106
+ "pageSize": 10,
107
+ "totalCount": 100
108
+ },
109
+ "response": [] // Response data
110
+ },
111
+ "post": {
112
+ "requestSchema": { // Request body validation schema
113
+ "name": "string",
114
+ "age": "number"
115
+ },
116
+ "response": {
117
+ "success": true
118
+ }
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ ## 🎯 API Examples
125
+
126
+ ### Basic CRUD Operations
127
+
128
+ #### Get Users List
129
+ ```bash
130
+ curl http://localhost:8080/api/users
131
+ ```
132
+
133
+ #### Get Single User
134
+ ```bash
135
+ curl http://localhost:8080/api/users/1
136
+ ```
137
+
138
+ #### Create User
139
+ ```bash
140
+ curl -X POST http://localhost:8080/api/users \
141
+ -H "Content-Type: application/json" \
142
+ -d '{"name":"Alice","age":25,"city":"Boston"}'
143
+ ```
144
+
145
+ #### Update User
146
+ ```bash
147
+ curl -X PUT http://localhost:8080/api/users/1 \
148
+ -H "Content-Type: application/json" \
149
+ -d '{"name":"Alice","age":26,"city":"Boston"}'
150
+ ```
151
+
152
+ #### Delete User
153
+ ```bash
154
+ curl -X DELETE http://localhost:8080/api/users/1
155
+ ```
156
+
157
+ ### Advanced Usage
158
+
159
+ #### Pagination
160
+ ```bash
161
+ # Get page 2 with 10 items per page
162
+ curl http://localhost:8080/api/users?page=2&pageSize=10
163
+ ```
164
+
165
+ #### Custom Response Headers
166
+ The server automatically adds these headers:
167
+ - `X-Total-Count`: Total number of items (for paginated responses)
168
+
169
+ ## 🔧 Advanced Configuration
170
+
171
+ ### Dynamic Routes
172
+
173
+ You can use URL parameters in routes:
174
+
175
+ ```json
176
+ {
177
+ "path": "/users/:id/posts",
178
+ "methods": {
179
+ "get": {
180
+ "type": "array",
181
+ "response": []
182
+ }
183
+ }
184
+ }
185
+ ```
186
+
187
+ ### Request Validation
188
+
189
+ Add schema validation for POST/PUT requests:
190
+
191
+ ```json
192
+ {
193
+ "requestSchema": {
194
+ "name": "string",
195
+ "age": "number",
196
+ "email": "string"
197
+ }
198
+ }
199
+ ```
200
+
201
+ ## 🤝 Contributing
202
+
203
+ 1. Fork the repository
204
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
205
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
206
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
207
+ 5. Open a Pull Request
208
+
209
+ ## 📄 License
210
+
211
+ MIT © [Xiong Haiyin]
212
+
213
+ ## 🙏 Acknowledgments
214
+
215
+ - Express.js for the excellent web framework
216
+ - All our contributors and users
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_1 = require("./index");
5
+ const configPath = process.argv[2] || 'data.json';
6
+ (0, index_1.startServer)(configPath);
@@ -0,0 +1,3 @@
1
+ export declare function startServer(configPath?: string): void;
2
+ export { MockServer } from './server';
3
+ export * from './types';
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.MockServer = void 0;
21
+ exports.startServer = startServer;
22
+ const fs_1 = __importDefault(require("fs"));
23
+ const path_1 = __importDefault(require("path"));
24
+ const server_1 = require("./server");
25
+ function startServer(configPath = 'data.json') {
26
+ const fullPath = path_1.default.resolve(process.cwd(), configPath);
27
+ try {
28
+ const configContent = fs_1.default.readFileSync(fullPath, 'utf-8');
29
+ const config = JSON.parse(configContent);
30
+ const server = new server_1.MockServer(config, configPath);
31
+ server.start();
32
+ }
33
+ catch (error) {
34
+ console.error('Failed to start server:', error);
35
+ process.exit(1);
36
+ }
37
+ }
38
+ if (require.main === module) {
39
+ startServer();
40
+ }
41
+ var server_2 = require("./server");
42
+ Object.defineProperty(exports, "MockServer", { enumerable: true, get: function () { return server_2.MockServer; } });
43
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,18 @@
1
+ import { Config } from './types';
2
+ export declare class MockServer {
3
+ private app;
4
+ private config;
5
+ private configPath;
6
+ constructor(config: Config, configPath?: string);
7
+ private setupMiddleware;
8
+ private setupRoutes;
9
+ private saveConfig;
10
+ private findUserById;
11
+ private getNextUserId;
12
+ private createRoute;
13
+ private handleRequest;
14
+ private handlePostRequest;
15
+ private handlePutRequest;
16
+ private handleDeleteRequest;
17
+ start(): void;
18
+ }
package/dist/server.js ADDED
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MockServer = void 0;
7
+ const express_1 = __importDefault(require("express"));
8
+ const cors_1 = __importDefault(require("cors"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ class MockServer {
12
+ constructor(config, configPath = 'data.json') {
13
+ this.app = (0, express_1.default)();
14
+ this.config = config;
15
+ this.configPath = path_1.default.resolve(process.cwd(), configPath);
16
+ this.setupMiddleware();
17
+ this.setupRoutes();
18
+ }
19
+ setupMiddleware() {
20
+ this.app.use((0, cors_1.default)());
21
+ this.app.use(express_1.default.json());
22
+ }
23
+ setupRoutes() {
24
+ this.config.routes.forEach((route) => {
25
+ Object.entries(route.methods).forEach(([method, methodConfig]) => {
26
+ this.createRoute(route.path, method, methodConfig);
27
+ });
28
+ });
29
+ }
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
+ createRoute(path, method, config) {
53
+ const fullPath = `${this.config.server.baseProxy}${path}`;
54
+ console.log(`创建路由: ${method.toUpperCase()} ${fullPath}`);
55
+ switch (method.toLowerCase()) {
56
+ case 'get':
57
+ this.app.get(fullPath, this.handleRequest(config));
58
+ break;
59
+ case 'post':
60
+ this.app.post(fullPath, this.handlePostRequest(config));
61
+ break;
62
+ case 'put':
63
+ this.app.put(`${fullPath}/:id`, this.handlePutRequest(config));
64
+ break;
65
+ case 'delete':
66
+ this.app.delete(`${fullPath}/:id`, this.handleDeleteRequest(config));
67
+ break;
68
+ }
69
+ }
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
+ start() {
142
+ this.app.listen(this.config.server.port, () => {
143
+ console.log(`Mock 服务器已启动:`);
144
+ console.log(`- 地址: http://localhost:${this.config.server.port}`);
145
+ console.log(`- 基础路径: ${this.config.server.baseProxy}`);
146
+ console.log('可用的接口:');
147
+ this.config.routes.forEach(route => {
148
+ Object.keys(route.methods).forEach(method => {
149
+ console.log(` ${method.toUpperCase()} http://localhost:${this.config.server.port}${this.config.server.baseProxy}${route.path}`);
150
+ });
151
+ });
152
+ });
153
+ }
154
+ }
155
+ exports.MockServer = MockServer;
@@ -0,0 +1,26 @@
1
+ export interface ServerConfig {
2
+ port: number;
3
+ baseProxy: string;
4
+ }
5
+ export interface PaginationConfig {
6
+ enabled: boolean;
7
+ pageSize: number;
8
+ totalCount: number;
9
+ }
10
+ export interface MethodConfig {
11
+ type?: 'array' | 'object';
12
+ pagination?: PaginationConfig;
13
+ response: any;
14
+ requestSchema?: Record<string, string>;
15
+ params?: string[];
16
+ }
17
+ export interface RouteConfig {
18
+ path: string;
19
+ methods: {
20
+ [key: string]: MethodConfig;
21
+ };
22
+ }
23
+ export interface Config {
24
+ server: ServerConfig;
25
+ routes: RouteConfig[];
26
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "json-api-mocker",
3
+ "version": "1.0.0",
4
+ "description": "一个基于 JSON 配置的 Mock 服务器",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "json-mock-server": "dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "README.ch.md"
14
+ ],
15
+ "scripts": {
16
+ "dev": "nodemon",
17
+ "build": "tsc",
18
+ "start": "node dist/index.js",
19
+ "test": "jest",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mock",
24
+ "server",
25
+ "json",
26
+ "api",
27
+ "typescript",
28
+ "rest",
29
+ "api-mock",
30
+ "mock-server"
31
+ ],
32
+ "author": "Xiong Haiyin",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/你的用户名/json-mock-server.git"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/你的用户名/json-mock-server/issues"
40
+ },
41
+ "homepage": "https://github.com/你的用户名/json-mock-server#readme",
42
+ "dependencies": {
43
+ "cors": "^2.8.5",
44
+ "express": "^4.17.1"
45
+ },
46
+ "devDependencies": {
47
+ "@types/cors": "^2.8.13",
48
+ "@types/express": "^4.17.13",
49
+ "@types/jest": "^27.5.2",
50
+ "@types/node": "^16.18.0",
51
+ "jest": "^27.5.1",
52
+ "nodemon": "^2.0.22",
53
+ "ts-jest": "^27.1.5",
54
+ "ts-node": "^10.9.1",
55
+ "typescript": "^4.9.5"
56
+ }
57
+ }