jgloo 1.4.0 → 1.6.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/CHANGELOG.md +40 -0
- package/README.md +40 -15
- package/cli +2 -2
- package/jgloo.js +7 -1
- package/package.json +4 -4
- package/rest.js +61 -48
- package/server.js +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
<a name="1.6.0"></a>
|
|
2
|
+
|
|
3
|
+
## [1.6.0](https://github.com/zosma180/jgloo/compare/1.5.2...1.6.0) (2022-02-20)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Added the optional "delay" property to the configuration
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<a name="1.5.2"></a>
|
|
12
|
+
|
|
13
|
+
## [1.5.2](https://github.com/zosma180/jgloo/compare/1.5.1...1.5.2) (2021-02-21)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- Fixed the folder path with space characters
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<a name="1.5.1"></a>
|
|
22
|
+
|
|
23
|
+
## [1.5.1](https://github.com/zosma180/jgloo/compare/1.5.0...1.5.1) (2021-02-17)
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
- Fixed the folder path for Windows environment
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<a name="1.5.0"></a>
|
|
32
|
+
|
|
33
|
+
## [1.5.0](https://github.com/zosma180/jgloo/compare/1.4.0...1.5.0) (2021-01-25)
|
|
34
|
+
|
|
35
|
+
### Features
|
|
36
|
+
|
|
37
|
+
- Added the optional "not" property to the default ReST API configuration
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
1
41
|
<a name="1.4.0"></a>
|
|
2
42
|
|
|
3
43
|
## [1.4.0](https://github.com/zosma180/jgloo/compare/1.3.0...1.4.0) (2020-06-30)
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ This project is based on the Node framework Express. The highlights are:
|
|
|
16
16
|
|
|
17
17
|
- Create a ReST API with two rows of code
|
|
18
18
|
- Create custom API easily
|
|
19
|
-
- Create custom middleware easily (
|
|
19
|
+
- Create custom middleware easily (e.g. auth check)
|
|
20
20
|
- Store data in accessible JSON files
|
|
21
21
|
- Reload the live changes of your mocks automatically (thanks to nodemon package)
|
|
22
22
|
- Expose a dedicated folder for the static files (images, assets etc...)
|
|
@@ -27,11 +27,11 @@ This project is based on the Node framework Express. The highlights are:
|
|
|
27
27
|
## Installation
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npm i -
|
|
30
|
+
npm i -D jgloo
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
After the installation create a folder "mock" in your project root (you can use another path and folder name if you want).
|
|
34
|
-
The **only requirement** is to create a subfolder "api" in your chosen path (
|
|
34
|
+
The **only requirement** is to create a subfolder "api" in your chosen path (e.g. "mock/api").
|
|
35
35
|
Now you are ready to [create your first API](#create-a-simple-api).
|
|
36
36
|
|
|
37
37
|
---
|
|
@@ -45,6 +45,7 @@ Now you are ready to [create your first API](#create-a-simple-api).
|
|
|
45
45
|
- [Where data are stored](#where-data-are-stored)
|
|
46
46
|
- [Expose the static files](#expose-the-static-files)
|
|
47
47
|
- [Handle requests with file uploads](#handle-requests-with-file-uploads)
|
|
48
|
+
- [Simulate network delay](#simulate-network-delay)
|
|
48
49
|
- [Run the server](#run-the-server)
|
|
49
50
|
|
|
50
51
|
---
|
|
@@ -53,7 +54,7 @@ Now you are ready to [create your first API](#create-a-simple-api).
|
|
|
53
54
|
|
|
54
55
|
To setup your first API create a new file "hello.js" in the "api" folder. The name of the file does not matter. Then insert the following snippet:
|
|
55
56
|
|
|
56
|
-
```
|
|
57
|
+
```javascript
|
|
57
58
|
module.exports = {
|
|
58
59
|
path: '/hello',
|
|
59
60
|
method: 'get',
|
|
@@ -72,7 +73,7 @@ You are ready to [run the server](#run-the-server) now.
|
|
|
72
73
|
|
|
73
74
|
To setup a ReST API, you have to create a new file in the "api" folder with the name you prefer and the following snippet:
|
|
74
75
|
|
|
75
|
-
```
|
|
76
|
+
```javascript
|
|
76
77
|
module.exports = {
|
|
77
78
|
path: '/user',
|
|
78
79
|
method: 'resource',
|
|
@@ -88,6 +89,17 @@ With these few rows of code will be created 6 routes:
|
|
|
88
89
|
- PATCH /user/:id : allow to merge an existent user data with the request body values and return it as response;
|
|
89
90
|
- DELETE /user/:id : allow to delete an existent user and return the deleted id.
|
|
90
91
|
|
|
92
|
+
If you want to skip any of the previous routes, you can add the "not" property:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
module.exports = {
|
|
96
|
+
path: '/user',
|
|
97
|
+
method: 'resource',
|
|
98
|
+
not: ['LIST']
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
The available values of the "not" property are ['LIST', 'READ', 'CREATE', 'UPDATE', 'PATCH', 'DELETE']
|
|
102
|
+
|
|
91
103
|
---
|
|
92
104
|
|
|
93
105
|
### Create a custom ReST API
|
|
@@ -95,7 +107,7 @@ With these few rows of code will be created 6 routes:
|
|
|
95
107
|
If you need to control the logic of your resources, you can create a custom API that read and/or write the data in the JSON database.
|
|
96
108
|
To achieve it create a new file in the "api" folder with the name you prefer and the following snippet:
|
|
97
109
|
|
|
98
|
-
```
|
|
110
|
+
```javascript
|
|
99
111
|
const { getResource, setResource } = require('jgloo');
|
|
100
112
|
|
|
101
113
|
module.exports = {
|
|
@@ -125,10 +137,10 @@ module.exports = {
|
|
|
125
137
|
|
|
126
138
|
### Create a middleware
|
|
127
139
|
|
|
128
|
-
To add a middleware, you have to create a folder "middlewares" in your chosen root path (
|
|
140
|
+
To add a middleware, you have to create a folder "middlewares" in your chosen root path (e.g. "mock/middlewares").
|
|
129
141
|
Then create a new file inside with the name you prefer and the following sample snippet:
|
|
130
142
|
|
|
131
|
-
```
|
|
143
|
+
```javascript
|
|
132
144
|
module.exports = (req, res, next) => {
|
|
133
145
|
const isAuthorized = req.get('Authorization') === 'my-token';
|
|
134
146
|
isAuthorized ? next() : res.sendStatus(401);
|
|
@@ -141,11 +153,11 @@ This sample code check for all routes if the "Authorization" header is set and i
|
|
|
141
153
|
|
|
142
154
|
### Where data are stored
|
|
143
155
|
|
|
144
|
-
The resources are stored in JSON files placed in the subfolder "db" of your chosen root path (
|
|
145
|
-
The [default ReST API](#create-a-default-rest-api) store the JSON file with the name generated by resource path replacing the slashes with the minus sign (
|
|
156
|
+
The resources are stored in JSON files placed in the subfolder "db" of your chosen root path (e.g. "mock/db").
|
|
157
|
+
The [default ReST API](#create-a-default-rest-api) store the JSON file with the name generated by resource path replacing the slashes with the minus sign (e.g. "/auth/user" will be stored as "auth-user.json").
|
|
146
158
|
If you want to specify the file name of the resources, you can set it as the "name" property of the API:
|
|
147
159
|
|
|
148
|
-
```
|
|
160
|
+
```javascript
|
|
149
161
|
module.exports = {
|
|
150
162
|
path: '/my/long/path',
|
|
151
163
|
method: 'resource',
|
|
@@ -159,7 +171,7 @@ With this code, the JSON file will be stored as "user.json".
|
|
|
159
171
|
|
|
160
172
|
### Expose the static files
|
|
161
173
|
|
|
162
|
-
To expose any static files you have to create the subfolder "static" in your chosen root path (
|
|
174
|
+
To expose any static files you have to create the subfolder "static" in your chosen root path (e.g. "mock/static") and put all the resources inside it.
|
|
163
175
|
The static content is reachable by "http://localhost:3000/static/...". That's it.
|
|
164
176
|
|
|
165
177
|
---
|
|
@@ -172,24 +184,37 @@ It's recommended to add the `static` folder in the `.gitignore` file.
|
|
|
172
184
|
|
|
173
185
|
---
|
|
174
186
|
|
|
187
|
+
### Simulate network delay
|
|
188
|
+
|
|
189
|
+
If you want to simulate a network delay, you can add the `delay` property to your API configuration:
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
module.exports = {
|
|
193
|
+
...
|
|
194
|
+
delay: 3 // Seconds
|
|
195
|
+
};
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
175
200
|
### Run the server
|
|
176
201
|
|
|
177
202
|
To run the server execute the following command in your project root:
|
|
178
203
|
|
|
179
204
|
```shell
|
|
180
|
-
jgloo
|
|
205
|
+
npx jgloo
|
|
181
206
|
```
|
|
182
207
|
|
|
183
208
|
The full optional parameters are:
|
|
184
209
|
|
|
185
210
|
```shell
|
|
186
|
-
jgloo -f [FOLDER] -p [PORT] -s [STATIC_URL]
|
|
211
|
+
npx jgloo -f [FOLDER] -p [PORT] -s [STATIC_URL]
|
|
187
212
|
```
|
|
188
213
|
|
|
189
214
|
For example:
|
|
190
215
|
|
|
191
216
|
```shell
|
|
192
|
-
jgloo -f 'mock' -p 3000 -s 'static'
|
|
217
|
+
npx jgloo -f 'mock' -p 3000 -s 'static'
|
|
193
218
|
```
|
|
194
219
|
|
|
195
220
|
- "**-f**" or "**--folder**": the folder where your mocks are placed. It's optional, by default it's the folder "mock".
|
package/cli
CHANGED
|
@@ -6,13 +6,13 @@ const { exec } = require('child_process');
|
|
|
6
6
|
const minimist = require('minimist');
|
|
7
7
|
|
|
8
8
|
const params = minimist(process.argv.slice(2));
|
|
9
|
-
const folder = path.join(process.
|
|
9
|
+
const folder = path.join(process.cwd(), params.f || params.folder || 'mock');
|
|
10
10
|
const port = params.p || params.port || 3000;
|
|
11
11
|
const staticUrl = params.s || params.static || 'static';
|
|
12
12
|
const server = `${__dirname}/server.js`;
|
|
13
13
|
|
|
14
14
|
const child = exec(
|
|
15
|
-
`nodemon --watch ${folder} --ignore "db/*.json" "${server}" "${folder}" "${port}" "${staticUrl}"`
|
|
15
|
+
`nodemon --watch "${folder}" --ignore "db/*.json" "${server}" "${folder}" "${port}" "${staticUrl}"`
|
|
16
16
|
);
|
|
17
17
|
|
|
18
18
|
child.stdout.on('data', (data) => console.log(String(data)));
|
package/jgloo.js
CHANGED
|
@@ -20,5 +20,11 @@ module.exports = {
|
|
|
20
20
|
if (!existsSync(db)) { mkdirSync(db); }
|
|
21
21
|
const path = `${db}/${name}.json`;
|
|
22
22
|
writeFileSync(path, JSON.stringify(value), 'utf8');
|
|
23
|
-
}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
getDelayMiddleware: (delay) => {
|
|
26
|
+
return (_, __, next) => {
|
|
27
|
+
setTimeout(() => next(), delay * 1000);
|
|
28
|
+
};
|
|
29
|
+
},
|
|
24
30
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jgloo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "The coldest mock server.",
|
|
5
|
-
"homepage": "https://github.com/zosma180/jgloo",
|
|
5
|
+
"homepage": "https://github.com/zosma180/jgloo#readme",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/zosma180/jgloo.git"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"deploy": "npm-deploy . ."
|
|
13
13
|
},
|
|
14
14
|
"bin": {
|
|
15
|
-
"jgloo": "
|
|
15
|
+
"jgloo": "cli"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"jgloo",
|
|
@@ -30,6 +30,6 @@
|
|
|
30
30
|
"express": "^4.17.1",
|
|
31
31
|
"minimist": "^1.2.5",
|
|
32
32
|
"multer": "^1.4.2",
|
|
33
|
-
"nodemon": "^2.0.
|
|
33
|
+
"nodemon": "^2.0.4"
|
|
34
34
|
}
|
|
35
35
|
}
|
package/rest.js
CHANGED
|
@@ -5,78 +5,91 @@ module.exports = {
|
|
|
5
5
|
configureResource: (app, config) => {
|
|
6
6
|
const fallback = config.path.split('/').filter(Boolean).join('-');
|
|
7
7
|
const resourceName = config.name || fallback;
|
|
8
|
+
const skips = config.not || [];
|
|
8
9
|
|
|
9
10
|
// List
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
if (skips.includes('LIST') === false) {
|
|
12
|
+
app.get(config.path, (req, res) => {
|
|
13
|
+
const resource = getResource(resourceName) || [];
|
|
14
|
+
res.json(resource);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
14
17
|
|
|
15
18
|
// Read
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
if (skips.includes('READ') === false) {
|
|
20
|
+
app.get(`${config.path}/:id`, (req, res) => {
|
|
21
|
+
const id = Number(req.params.id);
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
const resource = getResource(resourceName) || [];
|
|
24
|
+
const model = resource.find(r => r.id === id);
|
|
25
|
+
if (!model) { return res.sendStatus(404); }
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
res.json(model);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
25
30
|
|
|
26
31
|
// Create
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
if (skips.includes('CREATE') === false) {
|
|
33
|
+
app.post(config.path, (req, res) => {
|
|
34
|
+
const resource = getResource(resourceName) || [];
|
|
35
|
+
const model = req.body;
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
model.id = Date.now();
|
|
38
|
+
resource.push(model);
|
|
39
|
+
setResource(resourceName, resource);
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
res.json(model);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
37
44
|
|
|
38
45
|
// Update
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
if (skips.includes('UPDATE') === false) {
|
|
47
|
+
app.put(`${config.path}/:id`, (req, res) => {
|
|
48
|
+
const id = Number(req.params.id);
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
const resource = getResource(resourceName) || [];
|
|
51
|
+
const index = resource.findIndex(r => r.id === id);
|
|
52
|
+
if (index === -1) { return res.sendStatus(404); }
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
resource[index] = req.body;
|
|
55
|
+
resource[index].id = id;
|
|
56
|
+
setResource(resourceName, resource);
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
res.json(resource[index]);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
52
61
|
|
|
53
62
|
// Patch
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
if (skips.includes('PATCH') === false) {
|
|
64
|
+
app.patch(`${config.path}/:id`, (req, res) => {
|
|
65
|
+
const id = Number(req.params.id);
|
|
56
66
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
const resource = getResource(resourceName) || [];
|
|
68
|
+
const index = resource.findIndex(r => r.id === id);
|
|
69
|
+
if (index === -1) { return res.sendStatus(404); }
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
resource[index] = { ...resource[index], ...req.body };
|
|
72
|
+
resource[index].id = id;
|
|
73
|
+
setResource(resourceName, resource);
|
|
64
74
|
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
res.json(resource[index]);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
67
78
|
|
|
68
79
|
// Delete
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
if (skips.includes('DELETE') === false) {
|
|
81
|
+
app.delete(`${config.path}/:id`, (req, res) => {
|
|
82
|
+
const id = Number(req.params.id);
|
|
71
83
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
let resource = getResource(resourceName) || [];
|
|
85
|
+
const index = resource.findIndex(r => r.id === id);
|
|
86
|
+
if (index === -1) { return res.sendStatus(404); }
|
|
75
87
|
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
resource = resource.filter(r => r.id !== id);
|
|
89
|
+
setResource(resourceName, resource);
|
|
78
90
|
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
res.json(id);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
81
94
|
}
|
|
82
95
|
}
|
package/server.js
CHANGED
|
@@ -6,6 +6,7 @@ const bodyParser = require('body-parser');
|
|
|
6
6
|
const multer = require('multer');
|
|
7
7
|
|
|
8
8
|
const { configureResource } = require(path.join(__dirname, 'rest'));
|
|
9
|
+
const { getDelayMiddleware } = require(path.join(__dirname, 'jgloo'));
|
|
9
10
|
const app = express();
|
|
10
11
|
const params = process.argv.slice(2);
|
|
11
12
|
const root = params[0];
|
|
@@ -57,6 +58,11 @@ if (!api.length) {
|
|
|
57
58
|
api.forEach((file) => {
|
|
58
59
|
const config = require(path.join(apiPath, file));
|
|
59
60
|
|
|
61
|
+
// Add the API delay, if it is provided
|
|
62
|
+
if (config.delay) {
|
|
63
|
+
app.use(config.path, getDelayMiddleware(config.delay));
|
|
64
|
+
}
|
|
65
|
+
|
|
60
66
|
if (config.method === 'resource') {
|
|
61
67
|
// ReST resource
|
|
62
68
|
configureResource(app, config);
|