json-server 0.17.3 → 1.0.0-alpha.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/LICENSE +44 -20
- package/README.md +52 -589
- package/package.json +39 -92
- package/lib/cli/bin.js +0 -6
- package/lib/cli/index.js +0 -81
- package/lib/cli/run.js +0 -235
- package/lib/cli/utils/is.js +0 -19
- package/lib/cli/utils/load.js +0 -82
- package/lib/server/body-parser.js +0 -10
- package/lib/server/defaults.js +0 -80
- package/lib/server/index.js +0 -11
- package/lib/server/mixins.js +0 -85
- package/lib/server/rewriter.js +0 -16
- package/lib/server/router/delay.js +0 -12
- package/lib/server/router/get-full-url.js +0 -11
- package/lib/server/router/index.js +0 -103
- package/lib/server/router/nested.js +0 -29
- package/lib/server/router/plural.js +0 -305
- package/lib/server/router/singular.js +0 -64
- package/lib/server/router/validate-data.js +0 -19
- package/lib/server/router/write.js +0 -8
- package/lib/server/utils.js +0 -32
- package/public/favicon.ico +0 -0
- package/public/index.html +0 -85
- package/public/script.js +0 -76
- package/public/style.css +0 -113
package/lib/server/mixins.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
nanoid
|
|
5
|
-
} = require('nanoid');
|
|
6
|
-
|
|
7
|
-
const pluralize = require('pluralize');
|
|
8
|
-
|
|
9
|
-
module.exports = {
|
|
10
|
-
getRemovable,
|
|
11
|
-
createId,
|
|
12
|
-
deepQuery
|
|
13
|
-
}; // Returns document ids that have unsatisfied relations
|
|
14
|
-
// Example: a comment that references a post that doesn't exist
|
|
15
|
-
|
|
16
|
-
function getRemovable(db, opts) {
|
|
17
|
-
const _ = this;
|
|
18
|
-
|
|
19
|
-
const removable = [];
|
|
20
|
-
|
|
21
|
-
_.each(db, (coll, collName) => {
|
|
22
|
-
_.each(coll, doc => {
|
|
23
|
-
_.each(doc, (value, key) => {
|
|
24
|
-
if (new RegExp(`${opts.foreignKeySuffix}$`).test(key)) {
|
|
25
|
-
// Remove foreign key suffix and pluralize it
|
|
26
|
-
// Example postId -> posts
|
|
27
|
-
const refName = pluralize.plural(key.replace(new RegExp(`${opts.foreignKeySuffix}$`), '')); // Test if table exists
|
|
28
|
-
|
|
29
|
-
if (db[refName]) {
|
|
30
|
-
// Test if references is defined in table
|
|
31
|
-
const ref = _.getById(db[refName], value);
|
|
32
|
-
|
|
33
|
-
if (_.isUndefined(ref)) {
|
|
34
|
-
removable.push({
|
|
35
|
-
name: collName,
|
|
36
|
-
id: doc.id
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
return removable;
|
|
46
|
-
} // Return incremented id or uuid
|
|
47
|
-
// Used to override lodash-id's createId with utils.createId
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
function createId(coll) {
|
|
51
|
-
const _ = this;
|
|
52
|
-
|
|
53
|
-
const idProperty = _.__id();
|
|
54
|
-
|
|
55
|
-
if (_.isEmpty(coll)) {
|
|
56
|
-
return 1;
|
|
57
|
-
} else {
|
|
58
|
-
let id = _(coll).maxBy(idProperty)[idProperty]; // Increment integer id or generate string id
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return _.isFinite(id) ? ++id : nanoid(7);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function deepQuery(value, q) {
|
|
66
|
-
const _ = this;
|
|
67
|
-
|
|
68
|
-
if (value && q) {
|
|
69
|
-
if (_.isArray(value)) {
|
|
70
|
-
for (let i = 0; i < value.length; i++) {
|
|
71
|
-
if (_.deepQuery(value[i], q)) {
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
} else if (_.isObject(value) && !_.isArray(value)) {
|
|
76
|
-
for (const k in value) {
|
|
77
|
-
if (_.deepQuery(value[k], q)) {
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
} else if (value.toString().toLowerCase().indexOf(q) !== -1) {
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
package/lib/server/rewriter.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const express = require('express');
|
|
4
|
-
|
|
5
|
-
const rewrite = require('express-urlrewrite');
|
|
6
|
-
|
|
7
|
-
module.exports = routes => {
|
|
8
|
-
const router = express.Router();
|
|
9
|
-
router.get('/__rules', (req, res) => {
|
|
10
|
-
res.json(routes);
|
|
11
|
-
});
|
|
12
|
-
Object.keys(routes).forEach(key => {
|
|
13
|
-
router.use(rewrite(key, routes[key]));
|
|
14
|
-
});
|
|
15
|
-
return router;
|
|
16
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const pause = require('connect-pause');
|
|
4
|
-
|
|
5
|
-
module.exports = function delay(req, res, next) {
|
|
6
|
-
// NOTE: for some reason unknown to me, if the default is 0, the tests seems to add 2 seconds
|
|
7
|
-
// NOTE: to each test, a default value of 1 does not seem to be effected by that issue
|
|
8
|
-
const _delay = !isNaN(parseFloat(req.query._delay)) ? parseFloat(req.query._delay) : 1;
|
|
9
|
-
|
|
10
|
-
delete req.query._delay;
|
|
11
|
-
pause(_delay)(req, res, next);
|
|
12
|
-
};
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const express = require('express');
|
|
4
|
-
|
|
5
|
-
const methodOverride = require('method-override');
|
|
6
|
-
|
|
7
|
-
const _ = require('lodash');
|
|
8
|
-
|
|
9
|
-
const lodashId = require('lodash-id');
|
|
10
|
-
|
|
11
|
-
const low = require('lowdb');
|
|
12
|
-
|
|
13
|
-
const Memory = require('lowdb/adapters/Memory');
|
|
14
|
-
|
|
15
|
-
const FileSync = require('lowdb/adapters/FileSync');
|
|
16
|
-
|
|
17
|
-
const bodyParser = require('../body-parser');
|
|
18
|
-
|
|
19
|
-
const validateData = require('./validate-data');
|
|
20
|
-
|
|
21
|
-
const plural = require('./plural');
|
|
22
|
-
|
|
23
|
-
const nested = require('./nested');
|
|
24
|
-
|
|
25
|
-
const singular = require('./singular');
|
|
26
|
-
|
|
27
|
-
const mixins = require('../mixins');
|
|
28
|
-
|
|
29
|
-
module.exports = (db, opts) => {
|
|
30
|
-
opts = Object.assign({
|
|
31
|
-
foreignKeySuffix: 'Id',
|
|
32
|
-
_isFake: false
|
|
33
|
-
}, opts);
|
|
34
|
-
|
|
35
|
-
if (typeof db === 'string') {
|
|
36
|
-
db = low(new FileSync(db));
|
|
37
|
-
} else if (!_.has(db, '__chain__') || !_.has(db, '__wrapped__')) {
|
|
38
|
-
db = low(new Memory()).setState(db);
|
|
39
|
-
} // Create router
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const router = express.Router(); // Add middlewares
|
|
43
|
-
|
|
44
|
-
router.use(methodOverride());
|
|
45
|
-
router.use(bodyParser);
|
|
46
|
-
validateData(db.getState()); // Add lodash-id methods to db
|
|
47
|
-
|
|
48
|
-
db._.mixin(lodashId); // Add specific mixins
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
db._.mixin(mixins); // Expose database
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
router.db = db; // Expose render
|
|
55
|
-
|
|
56
|
-
router.render = (req, res) => {
|
|
57
|
-
res.jsonp(res.locals.data);
|
|
58
|
-
}; // GET /db
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
router.get('/db', (req, res) => {
|
|
62
|
-
res.jsonp(db.getState());
|
|
63
|
-
}); // Handle /:parent/:parentId/:resource
|
|
64
|
-
|
|
65
|
-
router.use(nested(opts)); // Create routes
|
|
66
|
-
|
|
67
|
-
db.forEach((value, key) => {
|
|
68
|
-
if (key === '$schema') {
|
|
69
|
-
// ignore $schema
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (_.isPlainObject(value)) {
|
|
74
|
-
router.use(`/${key}`, singular(db, key, opts));
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (_.isArray(value)) {
|
|
79
|
-
router.use(`/${key}`, plural(db, key, opts));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const sourceMessage = ''; // if (!_.isObject(source)) {
|
|
84
|
-
// sourceMessage = `in ${source}`
|
|
85
|
-
// }
|
|
86
|
-
|
|
87
|
-
const msg = `Type of "${key}" (${typeof value}) ${sourceMessage} is not supported. ` + `Use objects or arrays of objects.`;
|
|
88
|
-
throw new Error(msg);
|
|
89
|
-
}).value();
|
|
90
|
-
router.use((req, res) => {
|
|
91
|
-
if (!res.locals.data) {
|
|
92
|
-
res.status(404);
|
|
93
|
-
res.locals.data = {};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
router.render(req, res);
|
|
97
|
-
});
|
|
98
|
-
router.use((err, req, res, next) => {
|
|
99
|
-
console.error(err.stack);
|
|
100
|
-
res.status(500).send(err.stack);
|
|
101
|
-
});
|
|
102
|
-
return router;
|
|
103
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const express = require('express');
|
|
4
|
-
|
|
5
|
-
const pluralize = require('pluralize');
|
|
6
|
-
|
|
7
|
-
const delay = require('./delay');
|
|
8
|
-
|
|
9
|
-
module.exports = opts => {
|
|
10
|
-
const router = express.Router();
|
|
11
|
-
router.use(delay); // Rewrite URL (/:resource/:id/:nested -> /:nested) and request query
|
|
12
|
-
|
|
13
|
-
function get(req, res, next) {
|
|
14
|
-
const prop = pluralize.singular(req.params.resource);
|
|
15
|
-
req.query[`${prop}${opts.foreignKeySuffix}`] = req.params.id;
|
|
16
|
-
req.url = `/${req.params.nested}`;
|
|
17
|
-
next();
|
|
18
|
-
} // Rewrite URL (/:resource/:id/:nested -> /:nested) and request body
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
function post(req, res, next) {
|
|
22
|
-
const prop = pluralize.singular(req.params.resource);
|
|
23
|
-
req.body[`${prop}${opts.foreignKeySuffix}`] = req.params.id;
|
|
24
|
-
req.url = `/${req.params.nested}`;
|
|
25
|
-
next();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return router.get('/:resource/:id/:nested', get).post('/:resource/:id/:nested', post);
|
|
29
|
-
};
|
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
4
|
-
|
|
5
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
6
|
-
|
|
7
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
8
|
-
|
|
9
|
-
const express = require('express');
|
|
10
|
-
|
|
11
|
-
const _ = require('lodash');
|
|
12
|
-
|
|
13
|
-
const pluralize = require('pluralize');
|
|
14
|
-
|
|
15
|
-
const write = require('./write');
|
|
16
|
-
|
|
17
|
-
const getFullURL = require('./get-full-url');
|
|
18
|
-
|
|
19
|
-
const utils = require('../utils');
|
|
20
|
-
|
|
21
|
-
const delay = require('./delay');
|
|
22
|
-
|
|
23
|
-
module.exports = (db, name, opts) => {
|
|
24
|
-
// Create router
|
|
25
|
-
const router = express.Router();
|
|
26
|
-
router.use(delay); // Embed function used in GET /name and GET /name/id
|
|
27
|
-
|
|
28
|
-
function embed(resource, e) {
|
|
29
|
-
e && [].concat(e).forEach(externalResource => {
|
|
30
|
-
if (db.get(externalResource).value) {
|
|
31
|
-
const query = {};
|
|
32
|
-
const singularResource = pluralize.singular(name);
|
|
33
|
-
query[`${singularResource}${opts.foreignKeySuffix}`] = resource.id;
|
|
34
|
-
resource[externalResource] = db.get(externalResource).filter(query).value();
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
} // Expand function used in GET /name and GET /name/id
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
function expand(resource, e) {
|
|
41
|
-
e && [].concat(e).forEach(innerResource => {
|
|
42
|
-
const plural = pluralize(innerResource);
|
|
43
|
-
|
|
44
|
-
if (db.get(plural).value()) {
|
|
45
|
-
const prop = `${innerResource}${opts.foreignKeySuffix}`;
|
|
46
|
-
resource[innerResource] = db.get(plural).getById(resource[prop]).value();
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
} // GET /name
|
|
50
|
-
// GET /name?q=
|
|
51
|
-
// GET /name?attr=&attr=
|
|
52
|
-
// GET /name?_end=&
|
|
53
|
-
// GET /name?_start=&_end=&
|
|
54
|
-
// GET /name?_embed=&_expand=
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
function list(req, res, next) {
|
|
58
|
-
// Resource chain
|
|
59
|
-
let chain = db.get(name); // Remove q, _start, _end, ... from req.query to avoid filtering using those
|
|
60
|
-
// parameters
|
|
61
|
-
|
|
62
|
-
let q = req.query.q;
|
|
63
|
-
let _start = req.query._start;
|
|
64
|
-
let _end = req.query._end;
|
|
65
|
-
let _page = req.query._page;
|
|
66
|
-
const _sort = req.query._sort;
|
|
67
|
-
const _order = req.query._order;
|
|
68
|
-
let _limit = req.query._limit;
|
|
69
|
-
const _embed = req.query._embed;
|
|
70
|
-
const _expand = req.query._expand;
|
|
71
|
-
delete req.query.q;
|
|
72
|
-
delete req.query._start;
|
|
73
|
-
delete req.query._end;
|
|
74
|
-
delete req.query._sort;
|
|
75
|
-
delete req.query._order;
|
|
76
|
-
delete req.query._limit;
|
|
77
|
-
delete req.query._embed;
|
|
78
|
-
delete req.query._expand; // Automatically delete query parameters that can't be found
|
|
79
|
-
// in the database
|
|
80
|
-
|
|
81
|
-
Object.keys(req.query).forEach(query => {
|
|
82
|
-
const arr = db.get(name).value();
|
|
83
|
-
|
|
84
|
-
for (const i in arr) {
|
|
85
|
-
if (_.has(arr[i], query) || query === 'callback' || query === '_' || /_lte$/.test(query) || /_gte$/.test(query) || /_ne$/.test(query) || /_like$/.test(query)) return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
delete req.query[query];
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
if (q) {
|
|
92
|
-
// Full-text search
|
|
93
|
-
if (Array.isArray(q)) {
|
|
94
|
-
q = q[0];
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
q = q.toLowerCase();
|
|
98
|
-
chain = chain.filter(obj => {
|
|
99
|
-
for (const key in obj) {
|
|
100
|
-
const value = obj[key];
|
|
101
|
-
|
|
102
|
-
if (db._.deepQuery(value, q)) {
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return false;
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
Object.keys(req.query).forEach(key => {
|
|
112
|
-
// Don't take into account JSONP query parameters
|
|
113
|
-
// jQuery adds a '_' query parameter too
|
|
114
|
-
if (key !== 'callback' && key !== '_') {
|
|
115
|
-
// Always use an array, in case req.query is an array
|
|
116
|
-
const arr = [].concat(req.query[key]);
|
|
117
|
-
const isDifferent = /_ne$/.test(key);
|
|
118
|
-
const isRange = /_lte$/.test(key) || /_gte$/.test(key);
|
|
119
|
-
const isLike = /_like$/.test(key);
|
|
120
|
-
const path = key.replace(/(_lte|_gte|_ne|_like)$/, '');
|
|
121
|
-
chain = chain.filter(element => {
|
|
122
|
-
return arr.map(function (value) {
|
|
123
|
-
// get item value based on path
|
|
124
|
-
// i.e post.title -> 'foo'
|
|
125
|
-
const elementValue = _.get(element, path); // Prevent toString() failing on undefined or null values
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (elementValue === undefined || elementValue === null) {
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (isRange) {
|
|
133
|
-
const isLowerThan = /_gte$/.test(key);
|
|
134
|
-
return isLowerThan ? value <= elementValue : value >= elementValue;
|
|
135
|
-
} else if (isDifferent) {
|
|
136
|
-
return value !== elementValue.toString();
|
|
137
|
-
} else if (isLike) {
|
|
138
|
-
return new RegExp(value, 'i').test(elementValue.toString());
|
|
139
|
-
} else {
|
|
140
|
-
return value === elementValue.toString();
|
|
141
|
-
}
|
|
142
|
-
}).reduce((a, b) => isDifferent ? a && b : a || b);
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
}); // Sort
|
|
146
|
-
|
|
147
|
-
if (_sort) {
|
|
148
|
-
const _sortSet = _sort.split(',');
|
|
149
|
-
|
|
150
|
-
const _orderSet = (_order || '').split(',').map(s => s.toLowerCase());
|
|
151
|
-
|
|
152
|
-
chain = chain.orderBy(_sortSet, _orderSet);
|
|
153
|
-
} // Slice result
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (_end || _limit || _page) {
|
|
157
|
-
res.setHeader('X-Total-Count', chain.size());
|
|
158
|
-
res.setHeader('Access-Control-Expose-Headers', `X-Total-Count${_page ? ', Link' : ''}`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (_page) {
|
|
162
|
-
_page = parseInt(_page, 10);
|
|
163
|
-
_page = _page >= 1 ? _page : 1;
|
|
164
|
-
_limit = parseInt(_limit, 10) || 10;
|
|
165
|
-
const page = utils.getPage(chain.value(), _page, _limit);
|
|
166
|
-
const links = {};
|
|
167
|
-
const fullURL = getFullURL(req);
|
|
168
|
-
|
|
169
|
-
if (page.first) {
|
|
170
|
-
links.first = fullURL.replace(`page=${page.current}`, `page=${page.first}`);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (page.prev) {
|
|
174
|
-
links.prev = fullURL.replace(`page=${page.current}`, `page=${page.prev}`);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (page.next) {
|
|
178
|
-
links.next = fullURL.replace(`page=${page.current}`, `page=${page.next}`);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (page.last) {
|
|
182
|
-
links.last = fullURL.replace(`page=${page.current}`, `page=${page.last}`);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
res.links(links);
|
|
186
|
-
chain = _.chain(page.items);
|
|
187
|
-
} else if (_end) {
|
|
188
|
-
_start = parseInt(_start, 10) || 0;
|
|
189
|
-
_end = parseInt(_end, 10);
|
|
190
|
-
chain = chain.slice(_start, _end);
|
|
191
|
-
} else if (_limit) {
|
|
192
|
-
_start = parseInt(_start, 10) || 0;
|
|
193
|
-
_limit = parseInt(_limit, 10);
|
|
194
|
-
chain = chain.slice(_start, _start + _limit);
|
|
195
|
-
} // embed and expand
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
chain = chain.cloneDeep().forEach(function (element) {
|
|
199
|
-
embed(element, _embed);
|
|
200
|
-
expand(element, _expand);
|
|
201
|
-
});
|
|
202
|
-
res.locals.data = chain.value();
|
|
203
|
-
next();
|
|
204
|
-
} // GET /name/:id
|
|
205
|
-
// GET /name/:id?_embed=&_expand
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
function show(req, res, next) {
|
|
209
|
-
const _embed = req.query._embed;
|
|
210
|
-
const _expand = req.query._expand;
|
|
211
|
-
const resource = db.get(name).getById(req.params.id).value();
|
|
212
|
-
|
|
213
|
-
if (resource) {
|
|
214
|
-
// Clone resource to avoid making changes to the underlying object
|
|
215
|
-
const clone = _.cloneDeep(resource); // Embed other resources based on resource id
|
|
216
|
-
// /posts/1?_embed=comments
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
embed(clone, _embed); // Expand inner resources based on id
|
|
220
|
-
// /posts/1?_expand=user
|
|
221
|
-
|
|
222
|
-
expand(clone, _expand);
|
|
223
|
-
res.locals.data = clone;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
next();
|
|
227
|
-
} // POST /name
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
function create(req, res, next) {
|
|
231
|
-
let resource;
|
|
232
|
-
|
|
233
|
-
if (opts._isFake) {
|
|
234
|
-
const id = db.get(name).createId().value();
|
|
235
|
-
resource = _objectSpread(_objectSpread({}, req.body), {}, {
|
|
236
|
-
id
|
|
237
|
-
});
|
|
238
|
-
} else {
|
|
239
|
-
resource = db.get(name).insert(req.body).value();
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
res.setHeader('Access-Control-Expose-Headers', 'Location');
|
|
243
|
-
res.location(`${getFullURL(req)}/${resource.id}`);
|
|
244
|
-
res.status(201);
|
|
245
|
-
res.locals.data = resource;
|
|
246
|
-
next();
|
|
247
|
-
} // PUT /name/:id
|
|
248
|
-
// PATCH /name/:id
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
function update(req, res, next) {
|
|
252
|
-
const id = req.params.id;
|
|
253
|
-
let resource;
|
|
254
|
-
|
|
255
|
-
if (opts._isFake) {
|
|
256
|
-
resource = db.get(name).getById(id).value();
|
|
257
|
-
|
|
258
|
-
if (req.method === 'PATCH') {
|
|
259
|
-
resource = _objectSpread(_objectSpread({}, resource), req.body);
|
|
260
|
-
} else {
|
|
261
|
-
resource = _objectSpread(_objectSpread({}, req.body), {}, {
|
|
262
|
-
id: resource.id
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
} else {
|
|
266
|
-
let chain = db.get(name);
|
|
267
|
-
chain = req.method === 'PATCH' ? chain.updateById(id, req.body) : chain.replaceById(id, req.body);
|
|
268
|
-
resource = chain.value();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (resource) {
|
|
272
|
-
res.locals.data = resource;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
next();
|
|
276
|
-
} // DELETE /name/:id
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
function destroy(req, res, next) {
|
|
280
|
-
let resource;
|
|
281
|
-
|
|
282
|
-
if (opts._isFake) {
|
|
283
|
-
resource = db.get(name).value();
|
|
284
|
-
} else {
|
|
285
|
-
resource = db.get(name).removeById(req.params.id).value(); // Remove dependents documents
|
|
286
|
-
|
|
287
|
-
const removable = db._.getRemovable(db.getState(), opts);
|
|
288
|
-
|
|
289
|
-
removable.forEach(item => {
|
|
290
|
-
db.get(item.name).removeById(item.id).value();
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (resource) {
|
|
295
|
-
res.locals.data = {};
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
next();
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const w = write(db);
|
|
302
|
-
router.route('/').get(list).post(create, w);
|
|
303
|
-
router.route('/:id').get(show).put(update, w).patch(update, w).delete(destroy, w);
|
|
304
|
-
return router;
|
|
305
|
-
};
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
4
|
-
|
|
5
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
6
|
-
|
|
7
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
8
|
-
|
|
9
|
-
const express = require('express');
|
|
10
|
-
|
|
11
|
-
const write = require('./write');
|
|
12
|
-
|
|
13
|
-
const getFullURL = require('./get-full-url');
|
|
14
|
-
|
|
15
|
-
const delay = require('./delay');
|
|
16
|
-
|
|
17
|
-
module.exports = (db, name, opts) => {
|
|
18
|
-
const router = express.Router();
|
|
19
|
-
router.use(delay);
|
|
20
|
-
|
|
21
|
-
function show(req, res, next) {
|
|
22
|
-
res.locals.data = db.get(name).value();
|
|
23
|
-
next();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function create(req, res, next) {
|
|
27
|
-
if (opts._isFake) {
|
|
28
|
-
res.locals.data = req.body;
|
|
29
|
-
} else {
|
|
30
|
-
db.set(name, req.body).value();
|
|
31
|
-
res.locals.data = db.get(name).value();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
res.setHeader('Access-Control-Expose-Headers', 'Location');
|
|
35
|
-
res.location(`${getFullURL(req)}`);
|
|
36
|
-
res.status(201);
|
|
37
|
-
next();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function update(req, res, next) {
|
|
41
|
-
if (opts._isFake) {
|
|
42
|
-
if (req.method === 'PUT') {
|
|
43
|
-
res.locals.data = req.body;
|
|
44
|
-
} else {
|
|
45
|
-
const resource = db.get(name).value();
|
|
46
|
-
res.locals.data = _objectSpread(_objectSpread({}, resource), req.body);
|
|
47
|
-
}
|
|
48
|
-
} else {
|
|
49
|
-
if (req.method === 'PUT') {
|
|
50
|
-
db.set(name, req.body).value();
|
|
51
|
-
} else {
|
|
52
|
-
db.get(name).assign(req.body).value();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
res.locals.data = db.get(name).value();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
next();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const w = write(db);
|
|
62
|
-
router.route('/').get(show).post(create, w).put(update, w).patch(update, w);
|
|
63
|
-
return router;
|
|
64
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
|
|
5
|
-
function validateKey(key) {
|
|
6
|
-
if (key.indexOf('/') !== -1) {
|
|
7
|
-
const msg = [`Oops, found / character in database property '${key}'.`, '', "/ aren't supported, if you want to tweak default routes, see", 'https://github.com/typicode/json-server/#add-custom-routes'].join('\n');
|
|
8
|
-
throw new Error(msg);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
module.exports = obj => {
|
|
13
|
-
if (_.isPlainObject(obj)) {
|
|
14
|
-
Object.keys(obj).forEach(validateKey);
|
|
15
|
-
} else {
|
|
16
|
-
throw new Error(`Data must be an object. Found ${Array.isArray(obj) ? 'array' : typeof obj}.
|
|
17
|
-
'See https://github.com/typicode/json-server for example.`);
|
|
18
|
-
}
|
|
19
|
-
};
|
package/lib/server/utils.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
4
|
-
getPage
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
function getPage(array, page, perPage) {
|
|
8
|
-
const obj = {};
|
|
9
|
-
const start = (page - 1) * perPage;
|
|
10
|
-
const end = page * perPage;
|
|
11
|
-
obj.items = array.slice(start, end);
|
|
12
|
-
|
|
13
|
-
if (obj.items.length === 0) {
|
|
14
|
-
return obj;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (page > 1) {
|
|
18
|
-
obj.prev = page - 1;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (end < array.length) {
|
|
22
|
-
obj.next = page + 1;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (obj.items.length !== array.length) {
|
|
26
|
-
obj.current = page;
|
|
27
|
-
obj.first = 1;
|
|
28
|
-
obj.last = Math.ceil(array.length / perPage);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return obj;
|
|
32
|
-
}
|
package/public/favicon.ico
DELETED
|
Binary file
|