json-server 0.17.4 → 1.0.0-alpha.10

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.
@@ -1,26 +0,0 @@
1
- "use strict";
2
-
3
- const express = require('express');
4
- const pluralize = require('pluralize');
5
- const delay = require('./delay');
6
- module.exports = opts => {
7
- const router = express.Router();
8
- router.use(delay);
9
-
10
- // Rewrite URL (/:resource/:id/:nested -> /:nested) and request query
11
- function get(req, res, next) {
12
- const prop = pluralize.singular(req.params.resource);
13
- req.query[`${prop}${opts.foreignKeySuffix}`] = req.params.id;
14
- req.url = `/${req.params.nested}`;
15
- next();
16
- }
17
-
18
- // Rewrite URL (/:resource/:id/:nested -> /:nested) and request body
19
- function post(req, res, next) {
20
- const prop = pluralize.singular(req.params.resource);
21
- req.body[`${prop}${opts.foreignKeySuffix}`] = req.params.id;
22
- req.url = `/${req.params.nested}`;
23
- next();
24
- }
25
- return router.get('/:resource/:id/:nested', get).post('/:resource/:id/:nested', post);
26
- };
@@ -1,273 +0,0 @@
1
- "use strict";
2
-
3
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
- function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
- function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
7
- function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
8
- const express = require('express');
9
- const _ = require('lodash');
10
- const pluralize = require('pluralize');
11
- const write = require('./write');
12
- const getFullURL = require('./get-full-url');
13
- const utils = require('../utils');
14
- const delay = require('./delay');
15
- module.exports = (db, name, opts) => {
16
- // Create router
17
- const router = express.Router();
18
- router.use(delay);
19
-
20
- // Embed function used in GET /name and GET /name/id
21
- function embed(resource, e) {
22
- e && [].concat(e).forEach(externalResource => {
23
- if (db.get(externalResource).value) {
24
- const query = {};
25
- const singularResource = pluralize.singular(name);
26
- query[`${singularResource}${opts.foreignKeySuffix}`] = resource.id;
27
- resource[externalResource] = db.get(externalResource).filter(query).value();
28
- }
29
- });
30
- }
31
-
32
- // Expand function used in GET /name and GET /name/id
33
- function expand(resource, e) {
34
- e && [].concat(e).forEach(innerResource => {
35
- const plural = pluralize(innerResource);
36
- if (db.get(plural).value()) {
37
- const prop = `${innerResource}${opts.foreignKeySuffix}`;
38
- resource[innerResource] = db.get(plural).getById(resource[prop]).value();
39
- }
40
- });
41
- }
42
-
43
- // GET /name
44
- // GET /name?q=
45
- // GET /name?attr=&attr=
46
- // GET /name?_end=&
47
- // GET /name?_start=&_end=&
48
- // GET /name?_embed=&_expand=
49
- function list(req, res, next) {
50
- // Resource chain
51
- let chain = db.get(name);
52
-
53
- // Remove q, _start, _end, ... from req.query to avoid filtering using those
54
- // parameters
55
- let q = req.query.q;
56
- let _start = req.query._start;
57
- let _end = req.query._end;
58
- let _page = req.query._page;
59
- const _sort = req.query._sort;
60
- const _order = req.query._order;
61
- let _limit = req.query._limit;
62
- const _embed = req.query._embed;
63
- const _expand = req.query._expand;
64
- delete req.query.q;
65
- delete req.query._start;
66
- delete req.query._end;
67
- delete req.query._sort;
68
- delete req.query._order;
69
- delete req.query._limit;
70
- delete req.query._embed;
71
- delete req.query._expand;
72
-
73
- // Automatically delete query parameters that can't be found
74
- // in the database
75
- Object.keys(req.query).forEach(query => {
76
- const arr = db.get(name).value();
77
- for (const i in arr) {
78
- if (_.has(arr[i], query) || query === 'callback' || query === '_' || /_lte$/.test(query) || /_gte$/.test(query) || /_ne$/.test(query) || /_like$/.test(query)) return;
79
- }
80
- delete req.query[query];
81
- });
82
- if (q) {
83
- // Full-text search
84
- if (Array.isArray(q)) {
85
- q = q[0];
86
- }
87
- q = q.toLowerCase();
88
- chain = chain.filter(obj => {
89
- for (const key in obj) {
90
- const value = obj[key];
91
- if (db._.deepQuery(value, q)) {
92
- return true;
93
- }
94
- }
95
- return false;
96
- });
97
- }
98
- Object.keys(req.query).forEach(key => {
99
- // Don't take into account JSONP query parameters
100
- // jQuery adds a '_' query parameter too
101
- if (key !== 'callback' && key !== '_') {
102
- // Always use an array, in case req.query is an array
103
- const arr = [].concat(req.query[key]);
104
- const isDifferent = /_ne$/.test(key);
105
- const isRange = /_lte$/.test(key) || /_gte$/.test(key);
106
- const isLike = /_like$/.test(key);
107
- const path = key.replace(/(_lte|_gte|_ne|_like)$/, '');
108
- chain = chain.filter(element => {
109
- return arr.map(function (value) {
110
- // get item value based on path
111
- // i.e post.title -> 'foo'
112
- const elementValue = _.get(element, path);
113
-
114
- // Prevent toString() failing on undefined or null values
115
- if (elementValue === undefined || elementValue === null) {
116
- return undefined;
117
- }
118
- if (isRange) {
119
- const isLowerThan = /_gte$/.test(key);
120
- return isLowerThan ? value <= elementValue : value >= elementValue;
121
- } else if (isDifferent) {
122
- return value !== elementValue.toString();
123
- } else if (isLike) {
124
- return new RegExp(value, 'i').test(elementValue.toString());
125
- } else {
126
- return value === elementValue.toString();
127
- }
128
- }).reduce((a, b) => isDifferent ? a && b : a || b);
129
- });
130
- }
131
- });
132
-
133
- // Sort
134
- if (_sort) {
135
- const _sortSet = _sort.split(',');
136
- const _orderSet = (_order || '').split(',').map(s => s.toLowerCase());
137
- chain = chain.orderBy(_sortSet, _orderSet);
138
- }
139
-
140
- // Slice result
141
- if (_end || _limit || _page) {
142
- res.setHeader('X-Total-Count', chain.size());
143
- res.setHeader('Access-Control-Expose-Headers', `X-Total-Count${_page ? ', Link' : ''}`);
144
- }
145
- if (_page) {
146
- _page = parseInt(_page, 10);
147
- _page = _page >= 1 ? _page : 1;
148
- _limit = parseInt(_limit, 10) || 10;
149
- const page = utils.getPage(chain.value(), _page, _limit);
150
- const links = {};
151
- const fullURL = getFullURL(req);
152
- if (page.first) {
153
- links.first = fullURL.replace(`page=${page.current}`, `page=${page.first}`);
154
- }
155
- if (page.prev) {
156
- links.prev = fullURL.replace(`page=${page.current}`, `page=${page.prev}`);
157
- }
158
- if (page.next) {
159
- links.next = fullURL.replace(`page=${page.current}`, `page=${page.next}`);
160
- }
161
- if (page.last) {
162
- links.last = fullURL.replace(`page=${page.current}`, `page=${page.last}`);
163
- }
164
- res.links(links);
165
- chain = _.chain(page.items);
166
- } else if (_end) {
167
- _start = parseInt(_start, 10) || 0;
168
- _end = parseInt(_end, 10);
169
- chain = chain.slice(_start, _end);
170
- } else if (_limit) {
171
- _start = parseInt(_start, 10) || 0;
172
- _limit = parseInt(_limit, 10);
173
- chain = chain.slice(_start, _start + _limit);
174
- }
175
-
176
- // embed and expand
177
- chain = chain.cloneDeep().forEach(function (element) {
178
- embed(element, _embed);
179
- expand(element, _expand);
180
- });
181
- res.locals.data = chain.value();
182
- next();
183
- }
184
-
185
- // GET /name/:id
186
- // GET /name/:id?_embed=&_expand
187
- function show(req, res, next) {
188
- const _embed = req.query._embed;
189
- const _expand = req.query._expand;
190
- const resource = db.get(name).getById(req.params.id).value();
191
- if (resource) {
192
- // Clone resource to avoid making changes to the underlying object
193
- const clone = _.cloneDeep(resource);
194
-
195
- // Embed other resources based on resource id
196
- // /posts/1?_embed=comments
197
- embed(clone, _embed);
198
-
199
- // Expand inner resources based on id
200
- // /posts/1?_expand=user
201
- expand(clone, _expand);
202
- res.locals.data = clone;
203
- }
204
- next();
205
- }
206
-
207
- // POST /name
208
- function create(req, res, next) {
209
- let resource;
210
- if (opts._isFake) {
211
- const id = db.get(name).createId().value();
212
- resource = _objectSpread(_objectSpread({}, req.body), {}, {
213
- id
214
- });
215
- } else {
216
- resource = db.get(name).insert(req.body).value();
217
- }
218
- res.setHeader('Access-Control-Expose-Headers', 'Location');
219
- res.location(`${getFullURL(req)}/${resource.id}`);
220
- res.status(201);
221
- res.locals.data = resource;
222
- next();
223
- }
224
-
225
- // PUT /name/:id
226
- // PATCH /name/:id
227
- function update(req, res, next) {
228
- const id = req.params.id;
229
- let resource;
230
- if (opts._isFake) {
231
- resource = db.get(name).getById(id).value();
232
- if (req.method === 'PATCH') {
233
- resource = _objectSpread(_objectSpread({}, resource), req.body);
234
- } else {
235
- resource = _objectSpread(_objectSpread({}, req.body), {}, {
236
- id: resource.id
237
- });
238
- }
239
- } else {
240
- let chain = db.get(name);
241
- chain = req.method === 'PATCH' ? chain.updateById(id, req.body) : chain.replaceById(id, req.body);
242
- resource = chain.value();
243
- }
244
- if (resource) {
245
- res.locals.data = resource;
246
- }
247
- next();
248
- }
249
-
250
- // DELETE /name/:id
251
- function destroy(req, res, next) {
252
- let resource;
253
- if (opts._isFake) {
254
- resource = db.get(name).value();
255
- } else {
256
- resource = db.get(name).removeById(req.params.id).value();
257
-
258
- // Remove dependents documents
259
- const removable = db._.getRemovable(db.getState(), opts);
260
- removable.forEach(item => {
261
- db.get(item.name).removeById(item.id).value();
262
- });
263
- }
264
- if (resource) {
265
- res.locals.data = {};
266
- }
267
- next();
268
- }
269
- const w = write(db);
270
- router.route('/').get(list).post(create, w);
271
- router.route('/:id').get(show).put(update, w).patch(update, w).delete(destroy, w);
272
- return router;
273
- };
@@ -1,52 +0,0 @@
1
- "use strict";
2
-
3
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
- function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
- function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
7
- function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
8
- const express = require('express');
9
- const write = require('./write');
10
- const getFullURL = require('./get-full-url');
11
- const delay = require('./delay');
12
- module.exports = (db, name, opts) => {
13
- const router = express.Router();
14
- router.use(delay);
15
- function show(req, res, next) {
16
- res.locals.data = db.get(name).value();
17
- next();
18
- }
19
- function create(req, res, next) {
20
- if (opts._isFake) {
21
- res.locals.data = req.body;
22
- } else {
23
- db.set(name, req.body).value();
24
- res.locals.data = db.get(name).value();
25
- }
26
- res.setHeader('Access-Control-Expose-Headers', 'Location');
27
- res.location(`${getFullURL(req)}`);
28
- res.status(201);
29
- next();
30
- }
31
- function update(req, res, next) {
32
- if (opts._isFake) {
33
- if (req.method === 'PUT') {
34
- res.locals.data = req.body;
35
- } else {
36
- const resource = db.get(name).value();
37
- res.locals.data = _objectSpread(_objectSpread({}, resource), req.body);
38
- }
39
- } else {
40
- if (req.method === 'PUT') {
41
- db.set(name, req.body).value();
42
- } else {
43
- db.get(name).assign(req.body).value();
44
- }
45
- res.locals.data = db.get(name).value();
46
- }
47
- next();
48
- }
49
- const w = write(db);
50
- router.route('/').get(show).post(create, w).put(update, w).patch(update, w);
51
- return router;
52
- };
@@ -1,17 +0,0 @@
1
- "use strict";
2
-
3
- const _ = require('lodash');
4
- function validateKey(key) {
5
- if (key.indexOf('/') !== -1) {
6
- 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');
7
- throw new Error(msg);
8
- }
9
- }
10
- module.exports = obj => {
11
- if (_.isPlainObject(obj)) {
12
- Object.keys(obj).forEach(validateKey);
13
- } else {
14
- throw new Error(`Data must be an object. Found ${Array.isArray(obj) ? 'array' : typeof obj}.
15
- 'See https://github.com/typicode/json-server for example.`);
16
- }
17
- };
@@ -1,8 +0,0 @@
1
- "use strict";
2
-
3
- module.exports = function write(db) {
4
- return (req, res, next) => {
5
- db.write();
6
- next();
7
- };
8
- };
@@ -1,26 +0,0 @@
1
- "use strict";
2
-
3
- module.exports = {
4
- getPage
5
- };
6
- function getPage(array, page, perPage) {
7
- const obj = {};
8
- const start = (page - 1) * perPage;
9
- const end = page * perPage;
10
- obj.items = array.slice(start, end);
11
- if (obj.items.length === 0) {
12
- return obj;
13
- }
14
- if (page > 1) {
15
- obj.prev = page - 1;
16
- }
17
- if (end < array.length) {
18
- obj.next = page + 1;
19
- }
20
- if (obj.items.length !== array.length) {
21
- obj.current = page;
22
- obj.first = 1;
23
- obj.last = Math.ceil(array.length / perPage);
24
- }
25
- return obj;
26
- }
Binary file
package/public/index.html DELETED
@@ -1,85 +0,0 @@
1
- <html>
2
- <head>
3
- <link
4
- rel="stylesheet"
5
- href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
6
- integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay"
7
- crossorigin="anonymous"
8
- />
9
- <link rel="stylesheet" href="style.css" />
10
- <title>JSON Server</title>
11
- </head>
12
-
13
- <body>
14
- <header>
15
- <div class="container">
16
- <nav>
17
- <ul>
18
- <li class="title">
19
- JSON Server
20
- </li>
21
- <li>
22
- <a href="https://github.com/users/typicode/sponsorship">
23
- <i class="fas fa-heart"></i>GitHub Sponsors
24
- </a>
25
- </li>
26
- <li>
27
- <a href="https://my-json-server.typicode.com">
28
- <i class="fas fa-burn"></i>My JSON Server
29
- </a>
30
- </li>
31
- <li>
32
- <a href="https://thanks.typicode.com">
33
- <i class="far fa-laugh"></i>Supporters
34
- </a>
35
- </li>
36
- </ul>
37
- </nav>
38
- </div>
39
- </header>
40
- <main>
41
- <div class="container">
42
- <h1>Congrats!</h1>
43
- <p>
44
- You're successfully running JSON Server
45
- <br />
46
- ✧*。٩(ˊᗜˋ*)و✧*。
47
- </p>
48
-
49
- <div id="resources"></div>
50
-
51
- <p>
52
- To access and modify resources, you can use any HTTP method:
53
- </p>
54
- <p>
55
- <code>GET</code>
56
- <code>POST</code>
57
- <code>PUT</code>
58
- <code>PATCH</code>
59
- <code>DELETE</code>
60
- <code>OPTIONS</code>
61
- </p>
62
-
63
- <div id="custom-routes"></div>
64
-
65
- <h1>Documentation</h1>
66
- <p>
67
- <a href="https://github.com/typicode/json-server">
68
- README
69
- </a>
70
- </p>
71
- </div>
72
- </main>
73
-
74
- <footer>
75
- <div class="container">
76
- <p>
77
- To replace this page, create a
78
- <code>./public/index.html</code> file.
79
- </p>
80
- </div>
81
- </footer>
82
-
83
- <script src="script.js"></script>
84
- </body>
85
- </html>
package/public/script.js DELETED
@@ -1,76 +0,0 @@
1
- function ResourceItem({ name, length }) {
2
- return `
3
- <li>
4
- <a href="${name}">/${name}</a>
5
- <sup>${length ? `${length}x` : 'object'}</sup>
6
- </li>
7
- `
8
- }
9
-
10
- function ResourceList({ db }) {
11
- return `
12
- <ul>
13
- ${Object.keys(db)
14
- .map((name) =>
15
- ResourceItem({
16
- name,
17
- length: Array.isArray(db[name]) && db[name].length,
18
- }),
19
- )
20
- .join('')}
21
- </ul>
22
- `
23
- }
24
-
25
- function NoResources() {
26
- return `<p>No resources found</p>`
27
- }
28
-
29
- function ResourcesBlock({ db }) {
30
- return `
31
- <div>
32
- <h1>Resources</h1>
33
- ${Object.keys(db).length ? ResourceList({ db }) : NoResources()}
34
- </div>
35
- `
36
- }
37
-
38
- window
39
- .fetch('db')
40
- .then((response) => response.json())
41
- .then(
42
- (db) =>
43
- (document.getElementById('resources').innerHTML = ResourcesBlock({ db })),
44
- )
45
-
46
- function CustomRoutesBlock({ customRoutes }) {
47
- const rules = Object.keys(customRoutes)
48
- if (rules.length) {
49
- return `
50
- <div>
51
- <h1>Custom Routes</h1>
52
- <table>
53
- ${rules
54
- .map(
55
- (rule) =>
56
- `<tr>
57
- <td>${rule}</td>
58
- <td><code>⇢</code> ${customRoutes[rule]}</td>
59
- </tr>`,
60
- )
61
- .join('')}
62
- </table>
63
- </div>
64
- `
65
- }
66
- }
67
-
68
- window
69
- .fetch('__rules')
70
- .then((response) => response.json())
71
- .then(
72
- (customRoutes) =>
73
- (document.getElementById('custom-routes').innerHTML = CustomRoutesBlock({
74
- customRoutes,
75
- })),
76
- )
package/public/style.css DELETED
@@ -1,113 +0,0 @@
1
- body {
2
- display: flex;
3
- min-height: 100vh;
4
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
5
- Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
6
- flex-direction: column;
7
- padding: 0;
8
- margin: 0;
9
- color: #3b4252;
10
- letter-spacing: 0;
11
- }
12
-
13
- .container {
14
- max-width: 960px;
15
- margin: auto;
16
- padding: 1rem;
17
- }
18
-
19
- header {
20
- border-bottom: 1px solid #eee;
21
- }
22
-
23
- header a {
24
- color: inherit;
25
- text-decoration: none;
26
- }
27
-
28
- header a:hover {
29
- text-decoration: underline;
30
- }
31
-
32
- nav ul {
33
- display: flex;
34
- flex-wrap: nowrap;
35
- justify-content: space-between;
36
- }
37
-
38
- nav li.title {
39
- flex-grow: 5;
40
- text-align: left;
41
- font-weight: bold;
42
- font-size: 1.4rem;
43
- color: #3b4252;
44
- }
45
-
46
- nav li {
47
- flex-grow: 1;
48
- align-self: center;
49
- text-align: right;
50
- color: #4c566a;
51
- }
52
-
53
- .fa-heart {
54
- color: deeppink;
55
- }
56
-
57
- main {
58
- flex: 1;
59
- }
60
-
61
- footer {
62
- margin-top: 4rem;
63
- border-top: 1px solid #eee;
64
- }
65
-
66
- h1 {
67
- margin-top: 4rem;
68
- font-weight: normal;
69
- }
70
-
71
- i {
72
- margin-right: 0.5rem;
73
- }
74
-
75
- a {
76
- color: #5e81ac;
77
- }
78
-
79
- a:hover {
80
- color: #81a1c1;
81
- text-decoration: underline;
82
- }
83
-
84
- table {
85
- margin-left: 0;
86
- }
87
-
88
- td {
89
- border: 0;
90
- padding: 0 1em 0.5em 0;
91
- }
92
-
93
- td:first-child {
94
- width: 1%;
95
- white-space: nowrap;
96
- }
97
-
98
- ul {
99
- list-style-position: inside;
100
- padding-left: 0;
101
- }
102
-
103
- li {
104
- list-style-type: none;
105
- margin-bottom: 0.2rem;
106
- }
107
-
108
- code {
109
- padding: 0.2rem;
110
- margin: 0rem 0.2rem;
111
- border-radius: 0.2rem;
112
- background: #e5e9f0;
113
- }