json-server
Advanced tools
Comparing version 0.17.1 to 0.17.4
@@ -5,3 +5,2 @@ #!/usr/bin/env node | ||
require('please-upgrade-node')(require('../../package.json')); | ||
require('./')(); |
"use strict"; | ||
const yargs = require('yargs'); | ||
const run = require('./run'); | ||
const pkg = require('../../package.json'); | ||
module.exports = function () { | ||
@@ -79,4 +76,3 @@ const argv = yargs.config('config').usage('$0 [options] <source>').options({ | ||
}).boolean('watch').boolean('read-only').boolean('quiet').boolean('no-cors').boolean('no-gzip').help('help').alias('help', 'h').version(pkg.version).alias('version', 'v').example('$0 db.json', '').example('$0 file.js', '').example('$0 http://example.com/db.json', '').epilog('https://github.com/typicode/json-server').require(1, 'Missing <source> argument').argv; | ||
run(argv); | ||
}; |
"use strict"; | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const jph = require('json-parse-helpfulerror'); | ||
const _ = require('lodash'); | ||
const chalk = require('chalk'); | ||
const enableDestroy = require('server-destroy'); | ||
const pause = require('connect-pause'); | ||
const is = require('./utils/is'); | ||
const load = require('./utils/load'); | ||
const jsonServer = require('../server'); | ||
function prettyPrint(argv, object, rules) { | ||
@@ -27,11 +17,10 @@ const root = `http://${argv.host}:${argv.port}`; | ||
console.log(chalk.bold(' Resources')); | ||
for (const prop in object) { | ||
// skip printing $schema nodes | ||
if (prop === '$schema') continue; | ||
console.log(` ${root}/${prop}`); | ||
} | ||
if (rules) { | ||
console.log(); | ||
console.log(chalk.bold(' Other routes')); | ||
for (const rule in rules) { | ||
@@ -41,3 +30,2 @@ console.log(` ${rule} -> ${rules[rule]}`); | ||
} | ||
console.log(); | ||
@@ -48,3 +36,2 @@ console.log(chalk.bold(' Home')); | ||
} | ||
function createApp(db, routes, middlewares, argv) { | ||
@@ -65,10 +52,7 @@ const app = jsonServer.create(); | ||
}; | ||
if (argv.static) { | ||
defaultsOpts.static = path.join(process.cwd(), argv.static); | ||
} | ||
const defaults = jsonServer.defaults(defaultsOpts); | ||
app.use(defaults); | ||
if (routes) { | ||
@@ -78,11 +62,8 @@ const rewriter = jsonServer.rewriter(routes); | ||
} | ||
if (middlewares) { | ||
app.use(middlewares); | ||
} | ||
if (argv.delay) { | ||
app.use(pause(argv.delay)); | ||
} | ||
router.db._.id = argv.id; | ||
@@ -93,3 +74,2 @@ app.db = router.db; | ||
} | ||
module.exports = function (argv) { | ||
@@ -99,33 +79,29 @@ const source = argv._[0]; | ||
let server; | ||
if (!fs.existsSync(argv.snapshots)) { | ||
console.log(`Error: snapshots directory ${argv.snapshots} doesn't exist`); | ||
process.exit(1); | ||
} // noop log fn | ||
} | ||
// noop log fn | ||
if (argv.quiet) { | ||
console.log = () => {}; | ||
} | ||
console.log(); | ||
console.log(chalk.cyan(' \\{^_^}/ hi!')); | ||
function start(cb) { | ||
console.log(); | ||
console.log(chalk.gray(' Loading', source)); | ||
server = undefined; // create db and load object, JSON file, JS or HTTP database | ||
server = undefined; | ||
// create db and load object, JSON file, JS or HTTP database | ||
return load(source).then(db => { | ||
// Load additional routes | ||
let routes; | ||
if (argv.routes) { | ||
console.log(chalk.gray(' Loading', argv.routes)); | ||
routes = JSON.parse(fs.readFileSync(argv.routes)); | ||
} // Load middlewares | ||
} | ||
// Load middlewares | ||
let middlewares; | ||
if (argv.middlewares) { | ||
@@ -136,14 +112,18 @@ middlewares = argv.middlewares.map(function (m) { | ||
}); | ||
} // Done | ||
} | ||
// Done | ||
console.log(chalk.gray(' Done')); | ||
console.log(chalk.gray(' Done')); // Create app and server | ||
// Create app and server | ||
app = createApp(db, routes, middlewares, argv); | ||
server = app.listen(argv.port, argv.host); // Enhance with a destroy function | ||
server = app.listen(argv.port, argv.host); | ||
enableDestroy(server); // Display server informations | ||
// Enhance with a destroy function | ||
enableDestroy(server); | ||
prettyPrint(argv, db.getState(), routes); // Catch and handle any error occurring in the server process | ||
// Display server informations | ||
prettyPrint(argv, db.getState(), routes); | ||
// Catch and handle any error occurring in the server process | ||
process.on('uncaughtException', error => { | ||
@@ -154,10 +134,11 @@ if (error.errno === 'EADDRINUSE') console.log(chalk.red(`Cannot bind to the port ${error.port}. Please specify another port number either through --port argument or through the json-server.json configuration file`));else console.log('Some error occurred', error); | ||
}); | ||
} // Start server | ||
} | ||
// Start server | ||
start().then(() => { | ||
// Snapshot | ||
console.log(chalk.gray(' Type s + enter at any time to create a snapshot of the database')); // Support nohup | ||
console.log(chalk.gray(' Type s + enter at any time to create a snapshot of the database')); | ||
// Support nohup | ||
// https://github.com/typicode/json-server/issues/221 | ||
process.stdin.on('error', () => { | ||
@@ -176,12 +157,15 @@ console.log(` Error, can't read from stdin`); | ||
} | ||
}); // Watch files | ||
}); | ||
// Watch files | ||
if (argv.watch) { | ||
console.log(chalk.gray(' Watching...')); | ||
console.log(); | ||
const source = argv._[0]; // Can't watch URL | ||
const source = argv._[0]; | ||
if (is.URL(source)) throw new Error("Can't watch URL"); // Watch .js or .json file | ||
// Can't watch URL | ||
if (is.URL(source)) throw new Error("Can't watch URL"); | ||
// Watch .js or .json file | ||
// Since lowdb uses atomic writing, directory is watched instead of file | ||
const watchedDir = path.dirname(source); | ||
@@ -194,10 +178,7 @@ let readError = false; | ||
const watchedFile = path.resolve(watchedDir, file); | ||
if (watchedFile === path.resolve(source)) { | ||
if (is.FILE(watchedFile)) { | ||
let obj; | ||
try { | ||
obj = jph.parse(fs.readFileSync(watchedFile)); | ||
if (readError) { | ||
@@ -212,7 +193,6 @@ console.log(chalk.green(` Read error has been fixed :)`)); | ||
return; | ||
} // Compare .json file content with in memory database | ||
} | ||
// Compare .json file content with in memory database | ||
const isDatabaseDifferent = !_.isEqual(obj, app.db.getState()); | ||
if (isDatabaseDifferent) { | ||
@@ -225,4 +205,5 @@ console.log(chalk.gray(` ${source} has changed, reloading...`)); | ||
} | ||
}); // Watch routes | ||
}); | ||
// Watch routes | ||
if (argv.routes) { | ||
@@ -233,3 +214,2 @@ const watchedDir = path.dirname(argv.routes); | ||
const watchedFile = path.resolve(watchedDir, file); | ||
if (watchedFile === path.resolve(argv.routes)) { | ||
@@ -236,0 +216,0 @@ console.log(chalk.gray(` ${argv.routes} has changed, reloading...`)); |
@@ -8,13 +8,10 @@ "use strict"; | ||
}; | ||
function FILE(s) { | ||
return !URL(s) && /\.json$/.test(s); | ||
} | ||
function JS(s) { | ||
return !URL(s) && /\.js$/.test(s); | ||
return !URL(s) && /\.c?js$/.test(s); | ||
} | ||
function URL(s) { | ||
return /^(http|https):/.test(s); | ||
} |
"use strict"; | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const http = require('http'); | ||
const https = require('https'); | ||
const low = require('lowdb'); | ||
const FileAsync = require('lowdb/adapters/FileAsync'); | ||
const Memory = require('lowdb/adapters/Memory'); | ||
const is = require('./is'); | ||
const chalk = require('chalk'); | ||
const example = { | ||
@@ -36,3 +27,2 @@ posts: [{ | ||
}; | ||
module.exports = function (source) { | ||
@@ -47,8 +37,7 @@ return new Promise((resolve, reject) => { | ||
} | ||
resolve(low(new FileAsync(source))); | ||
} else if (is.URL(source)) { | ||
// Normalize the source into a URL object. | ||
const sourceUrl = new URL(source); // Pick the client based on the protocol scheme | ||
const sourceUrl = new URL(source); | ||
// Pick the client based on the protocol scheme | ||
const client = sourceUrl.protocol === 'https:' ? https : http; | ||
@@ -70,10 +59,8 @@ client.get(sourceUrl, res => { | ||
delete require.cache[filename]; | ||
const dataFn = require(filename); | ||
if (typeof dataFn !== 'function') { | ||
throw new Error('The database is a JavaScript file but the export is not a function.'); | ||
} // Run dataFn to generate data | ||
} | ||
// Run dataFn to generate data | ||
const data = dataFn(); | ||
@@ -80,0 +67,0 @@ resolve(low(new Memory()).setState(data)); |
"use strict"; | ||
const bodyParser = require('body-parser'); | ||
module.exports = [bodyParser.json({ | ||
@@ -6,0 +5,0 @@ limit: '10mb', |
"use strict"; | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const express = require('express'); | ||
const logger = require('morgan'); | ||
const cors = require('cors'); | ||
const compression = require('compression'); | ||
const errorhandler = require('errorhandler'); | ||
const bodyParser = require('./body-parser'); | ||
module.exports = function (opts) { | ||
@@ -27,9 +19,10 @@ const userDir = path.join(process.cwd(), 'public'); | ||
}, opts); | ||
const arr = []; // Compress all requests | ||
const arr = []; | ||
// Compress all requests | ||
if (!opts.noGzip) { | ||
arr.push(compression()); | ||
} // Enable CORS for all the requests, including static files | ||
} | ||
// Enable CORS for all the requests, including static files | ||
if (!opts.noCors) { | ||
@@ -41,11 +34,11 @@ arr.push(cors({ | ||
} | ||
if (process.env.NODE_ENV === 'development') { | ||
// only use in development | ||
arr.push(errorhandler()); | ||
} // Serve static files | ||
} | ||
// Serve static files | ||
arr.push(express.static(opts.static)); | ||
arr.push(express.static(opts.static)); // Logger | ||
// Logger | ||
if (opts.logger) { | ||
@@ -55,6 +48,6 @@ arr.push(logger('dev', { | ||
})); | ||
} // No cache for IE | ||
} | ||
// No cache for IE | ||
// https://support.microsoft.com/en-us/kb/234067 | ||
arr.push((req, res, next) => { | ||
@@ -65,4 +58,5 @@ res.header('Cache-Control', 'no-cache'); | ||
next(); | ||
}); // Read-only | ||
}); | ||
// Read-only | ||
if (opts.readOnly) { | ||
@@ -76,10 +70,9 @@ arr.push((req, res, next) => { | ||
}); | ||
} // Add middlewares | ||
} | ||
// Add middlewares | ||
if (opts.bodyParser) { | ||
arr.push(bodyParser); | ||
} | ||
return arr; | ||
}; |
"use strict"; | ||
const express = require('express'); | ||
module.exports = { | ||
@@ -6,0 +5,0 @@ create: () => express().set('json spaces', 2), |
@@ -6,5 +6,3 @@ "use strict"; | ||
} = require('nanoid'); | ||
const pluralize = require('pluralize'); | ||
module.exports = { | ||
@@ -14,10 +12,9 @@ getRemovable, | ||
deepQuery | ||
}; // Returns document ids that have unsatisfied relations | ||
}; | ||
// Returns document ids that have unsatisfied relations | ||
// Example: a comment that references a post that doesn't exist | ||
function getRemovable(db, opts) { | ||
const _ = this; | ||
const removable = []; | ||
_.each(db, (coll, collName) => { | ||
@@ -29,8 +26,7 @@ _.each(coll, doc => { | ||
// Example postId -> posts | ||
const refName = pluralize.plural(key.replace(new RegExp(`${opts.foreignKeySuffix}$`), '')); // Test if table exists | ||
const refName = pluralize.plural(key.replace(new RegExp(`${opts.foreignKeySuffix}$`), '')); | ||
// Test if table exists | ||
if (db[refName]) { | ||
// Test if references is defined in table | ||
const ref = _.getById(db[refName], value); | ||
if (_.isUndefined(ref)) { | ||
@@ -47,26 +43,21 @@ removable.push({ | ||
}); | ||
return removable; | ||
} | ||
return removable; | ||
} // Return incremented id or uuid | ||
// Return incremented id or uuid | ||
// Used to override lodash-id's createId with utils.createId | ||
function createId(coll) { | ||
const _ = this; | ||
const idProperty = _.__id(); | ||
if (_.isEmpty(coll)) { | ||
return 1; | ||
} else { | ||
let id = _(coll).maxBy(idProperty)[idProperty]; // Increment integer id or generate string id | ||
let id = _(coll).maxBy(idProperty)[idProperty]; | ||
// Increment integer id or generate string id | ||
return _.isFinite(id) ? ++id : nanoid(7); | ||
} | ||
} | ||
function deepQuery(value, q) { | ||
const _ = this; | ||
if (value && q) { | ||
@@ -73,0 +64,0 @@ if (_.isArray(value)) { |
"use strict"; | ||
const express = require('express'); | ||
const rewrite = require('express-urlrewrite'); | ||
module.exports = routes => { | ||
@@ -8,0 +6,0 @@ const router = express.Router(); |
"use strict"; | ||
const pause = require('connect-pause'); | ||
module.exports = function delay(req, res, next) { | ||
@@ -9,5 +8,4 @@ // NOTE: for some reason unknown to me, if the default is 0, the tests seems to add 2 seconds | ||
const _delay = !isNaN(parseFloat(req.query._delay)) ? parseFloat(req.query._delay) : 1; | ||
delete req.query._delay; | ||
pause(_delay)(req, res, next); | ||
}; |
"use strict"; | ||
const url = require('url'); | ||
module.exports = function getFullURL(req) { | ||
@@ -6,0 +5,0 @@ const root = url.format({ |
"use strict"; | ||
const express = require('express'); | ||
const methodOverride = require('method-override'); | ||
const _ = require('lodash'); | ||
const lodashId = require('lodash-id'); | ||
const low = require('lowdb'); | ||
const Memory = require('lowdb/adapters/Memory'); | ||
const FileSync = require('lowdb/adapters/FileSync'); | ||
const bodyParser = require('../body-parser'); | ||
const validateData = require('./validate-data'); | ||
const plural = require('./plural'); | ||
const nested = require('./nested'); | ||
const singular = require('./singular'); | ||
const mixins = require('../mixins'); | ||
module.exports = (db, opts) => { | ||
@@ -34,3 +21,2 @@ opts = Object.assign({ | ||
}, opts); | ||
if (typeof db === 'string') { | ||
@@ -40,31 +26,40 @@ db = low(new FileSync(db)); | ||
db = low(new Memory()).setState(db); | ||
} // Create router | ||
} | ||
// Create router | ||
const router = express.Router(); | ||
const router = express.Router(); // Add middlewares | ||
// Add middlewares | ||
router.use(methodOverride()); | ||
router.use(bodyParser); | ||
validateData(db.getState()); // Add lodash-id methods to db | ||
validateData(db.getState()); | ||
db._.mixin(lodashId); // Add specific mixins | ||
// Add lodash-id methods to db | ||
db._.mixin(lodashId); | ||
// Add specific mixins | ||
db._.mixin(mixins); | ||
db._.mixin(mixins); // Expose database | ||
// Expose database | ||
router.db = db; | ||
router.db = db; // Expose render | ||
// Expose render | ||
router.render = (req, res) => { | ||
res.jsonp(res.locals.data); | ||
}; // GET /db | ||
}; | ||
// GET /db | ||
router.get('/db', (req, res) => { | ||
res.jsonp(db.getState()); | ||
}); // Handle /:parent/:parentId/:resource | ||
}); | ||
router.use(nested(opts)); // Create routes | ||
// Handle /:parent/:parentId/:resource | ||
router.use(nested(opts)); | ||
// Create routes | ||
db.forEach((value, key) => { | ||
if (key === '$schema') { | ||
// ignore $schema | ||
return; | ||
} | ||
if (_.isPlainObject(value)) { | ||
@@ -74,3 +69,2 @@ router.use(`/${key}`, singular(db, key, opts)); | ||
} | ||
if (_.isArray(value)) { | ||
@@ -80,4 +74,4 @@ router.use(`/${key}`, plural(db, key, opts)); | ||
} | ||
const sourceMessage = ''; // if (!_.isObject(source)) { | ||
const sourceMessage = ''; | ||
// if (!_.isObject(source)) { | ||
// sourceMessage = `in ${source}` | ||
@@ -94,3 +88,2 @@ // } | ||
} | ||
router.render(req, res); | ||
@@ -97,0 +90,0 @@ }); |
"use strict"; | ||
const express = require('express'); | ||
const pluralize = require('pluralize'); | ||
const delay = require('./delay'); | ||
module.exports = opts => { | ||
const router = express.Router(); | ||
router.use(delay); // Rewrite URL (/:resource/:id/:nested -> /:nested) and request query | ||
router.use(delay); | ||
// Rewrite URL (/:resource/:id/:nested -> /:nested) and request query | ||
function get(req, res, next) { | ||
@@ -18,5 +16,5 @@ const prop = pluralize.singular(req.params.resource); | ||
next(); | ||
} // Rewrite URL (/:resource/:id/:nested -> /:nested) and request body | ||
} | ||
// Rewrite URL (/:resource/:id/:nested -> /:nested) and request body | ||
function post(req, res, next) { | ||
@@ -28,4 +26,3 @@ const prop = pluralize.singular(req.params.resource); | ||
} | ||
return router.get('/:resource/:id/:nested', get).post('/:resource/:id/:nested', post); | ||
}; |
"use strict"; | ||
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; } | ||
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; } | ||
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; } | ||
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; } | ||
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; } | ||
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; } | ||
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } | ||
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); } | ||
const express = require('express'); | ||
const _ = require('lodash'); | ||
const pluralize = require('pluralize'); | ||
const write = require('./write'); | ||
const getFullURL = require('./get-full-url'); | ||
const utils = require('../utils'); | ||
const delay = require('./delay'); | ||
module.exports = (db, name, opts) => { | ||
// Create router | ||
const router = express.Router(); | ||
router.use(delay); // Embed function used in GET /name and GET /name/id | ||
router.use(delay); | ||
// Embed function used in GET /name and GET /name/id | ||
function embed(resource, e) { | ||
@@ -37,9 +30,8 @@ e && [].concat(e).forEach(externalResource => { | ||
}); | ||
} // Expand function used in GET /name and GET /name/id | ||
} | ||
// Expand function used in GET /name and GET /name/id | ||
function expand(resource, e) { | ||
e && [].concat(e).forEach(innerResource => { | ||
const plural = pluralize(innerResource); | ||
if (db.get(plural).value()) { | ||
@@ -50,3 +42,5 @@ const prop = `${innerResource}${opts.foreignKeySuffix}`; | ||
}); | ||
} // GET /name | ||
} | ||
// GET /name | ||
// GET /name?q= | ||
@@ -57,9 +51,8 @@ // GET /name?attr=&attr= | ||
// GET /name?_embed=&_expand= | ||
function list(req, res, next) { | ||
// Resource chain | ||
let chain = db.get(name); // Remove q, _start, _end, ... from req.query to avoid filtering using those | ||
let chain = db.get(name); | ||
// Remove q, _start, _end, ... from req.query to avoid filtering using those | ||
// parameters | ||
let q = req.query.q; | ||
@@ -81,15 +74,13 @@ let _start = req.query._start; | ||
delete req.query._embed; | ||
delete req.query._expand; // Automatically delete query parameters that can't be found | ||
delete req.query._expand; | ||
// Automatically delete query parameters that can't be found | ||
// in the database | ||
Object.keys(req.query).forEach(query => { | ||
const arr = db.get(name).value(); | ||
for (const i in arr) { | ||
if (_.has(arr[i], query) || query === 'callback' || query === '_' || /_lte$/.test(query) || /_gte$/.test(query) || /_ne$/.test(query) || /_like$/.test(query)) return; | ||
} | ||
delete req.query[query]; | ||
}); | ||
if (q) { | ||
@@ -100,3 +91,2 @@ // Full-text search | ||
} | ||
q = q.toLowerCase(); | ||
@@ -106,3 +96,2 @@ chain = chain.filter(obj => { | ||
const value = obj[key]; | ||
if (db._.deepQuery(value, q)) { | ||
@@ -112,7 +101,5 @@ return true; | ||
} | ||
return false; | ||
}); | ||
} | ||
Object.keys(req.query).forEach(key => { | ||
@@ -132,9 +119,8 @@ // Don't take into account JSONP query parameters | ||
// i.e post.title -> 'foo' | ||
const elementValue = _.get(element, path); // Prevent toString() failing on undefined or null values | ||
const elementValue = _.get(element, path); | ||
// Prevent toString() failing on undefined or null values | ||
if (elementValue === undefined || elementValue === null) { | ||
return undefined; | ||
} | ||
if (isRange) { | ||
@@ -153,13 +139,12 @@ const isLowerThan = /_gte$/.test(key); | ||
} | ||
}); // Sort | ||
}); | ||
// Sort | ||
if (_sort) { | ||
const _sortSet = _sort.split(','); | ||
const _orderSet = (_order || '').split(',').map(s => s.toLowerCase()); | ||
chain = chain.orderBy(_sortSet, _orderSet); | ||
} // Slice result | ||
} | ||
// Slice result | ||
if (_end || _limit || _page) { | ||
@@ -169,3 +154,2 @@ res.setHeader('X-Total-Count', chain.size()); | ||
} | ||
if (_page) { | ||
@@ -178,19 +162,14 @@ _page = parseInt(_page, 10); | ||
const fullURL = getFullURL(req); | ||
if (page.first) { | ||
links.first = fullURL.replace(`page=${page.current}`, `page=${page.first}`); | ||
} | ||
if (page.prev) { | ||
links.prev = fullURL.replace(`page=${page.current}`, `page=${page.prev}`); | ||
} | ||
if (page.next) { | ||
links.next = fullURL.replace(`page=${page.current}`, `page=${page.next}`); | ||
} | ||
if (page.last) { | ||
links.last = fullURL.replace(`page=${page.current}`, `page=${page.last}`); | ||
} | ||
res.links(links); | ||
@@ -206,5 +185,5 @@ chain = _.chain(page.items); | ||
chain = chain.slice(_start, _start + _limit); | ||
} // embed and expand | ||
} | ||
// embed and expand | ||
chain = chain.cloneDeep().forEach(function (element) { | ||
@@ -216,6 +195,6 @@ embed(element, _embed); | ||
next(); | ||
} // GET /name/:id | ||
} | ||
// GET /name/:id | ||
// GET /name/:id?_embed=&_expand | ||
function show(req, res, next) { | ||
@@ -225,23 +204,21 @@ const _embed = req.query._embed; | ||
const resource = db.get(name).getById(req.params.id).value(); | ||
if (resource) { | ||
// Clone resource to avoid making changes to the underlying object | ||
const clone = _.cloneDeep(resource); // Embed other resources based on resource id | ||
const clone = _.cloneDeep(resource); | ||
// Embed other resources based on resource id | ||
// /posts/1?_embed=comments | ||
embed(clone, _embed); | ||
embed(clone, _embed); // Expand inner resources based on id | ||
// Expand inner resources based on id | ||
// /posts/1?_expand=user | ||
expand(clone, _expand); | ||
res.locals.data = clone; | ||
} | ||
next(); | ||
} // POST /name | ||
} | ||
// POST /name | ||
function create(req, res, next) { | ||
let resource; | ||
if (opts._isFake) { | ||
@@ -255,3 +232,2 @@ const id = db.get(name).createId().value(); | ||
} | ||
res.setHeader('Access-Control-Expose-Headers', 'Location'); | ||
@@ -262,13 +238,11 @@ res.location(`${getFullURL(req)}/${resource.id}`); | ||
next(); | ||
} // PUT /name/:id | ||
} | ||
// PUT /name/:id | ||
// PATCH /name/:id | ||
function update(req, res, next) { | ||
const id = req.params.id; | ||
let resource; | ||
if (opts._isFake) { | ||
resource = db.get(name).getById(id).value(); | ||
if (req.method === 'PATCH') { | ||
@@ -286,21 +260,18 @@ resource = _objectSpread(_objectSpread({}, resource), req.body); | ||
} | ||
if (resource) { | ||
res.locals.data = resource; | ||
} | ||
next(); | ||
} // DELETE /name/:id | ||
} | ||
// DELETE /name/:id | ||
function destroy(req, res, next) { | ||
let resource; | ||
if (opts._isFake) { | ||
resource = db.get(name).value(); | ||
} else { | ||
resource = db.get(name).removeById(req.params.id).value(); // Remove dependents documents | ||
resource = db.get(name).removeById(req.params.id).value(); | ||
// Remove dependents documents | ||
const removable = db._.getRemovable(db.getState(), opts); | ||
removable.forEach(item => { | ||
@@ -310,10 +281,7 @@ db.get(item.name).removeById(item.id).value(); | ||
} | ||
if (resource) { | ||
res.locals.data = {}; | ||
} | ||
next(); | ||
} | ||
const w = write(db); | ||
@@ -320,0 +288,0 @@ router.route('/').get(list).post(create, w); |
"use strict"; | ||
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; } | ||
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; } | ||
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; } | ||
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; } | ||
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; } | ||
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; } | ||
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } | ||
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); } | ||
const express = require('express'); | ||
const write = require('./write'); | ||
const getFullURL = require('./get-full-url'); | ||
const delay = require('./delay'); | ||
module.exports = (db, name, opts) => { | ||
const router = express.Router(); | ||
router.use(delay); | ||
function show(req, res, next) { | ||
@@ -25,3 +19,2 @@ res.locals.data = db.get(name).value(); | ||
} | ||
function create(req, res, next) { | ||
@@ -34,3 +27,2 @@ if (opts._isFake) { | ||
} | ||
res.setHeader('Access-Control-Expose-Headers', 'Location'); | ||
@@ -41,3 +33,2 @@ res.location(`${getFullURL(req)}`); | ||
} | ||
function update(req, res, next) { | ||
@@ -57,9 +48,6 @@ if (opts._isFake) { | ||
} | ||
res.locals.data = db.get(name).value(); | ||
} | ||
next(); | ||
} | ||
const w = write(db); | ||
@@ -66,0 +54,0 @@ router.route('/').get(show).post(create, w).put(update, w).patch(update, w); |
"use strict"; | ||
const _ = require('lodash'); | ||
function validateKey(key) { | ||
@@ -11,3 +10,2 @@ if (key.indexOf('/') !== -1) { | ||
} | ||
module.exports = obj => { | ||
@@ -17,4 +15,5 @@ if (_.isPlainObject(obj)) { | ||
} else { | ||
throw new Error(`Data must be an object. Found ${typeof obj}.` + 'See https://github.com/typicode/json-server for example.'); | ||
throw new Error(`Data must be an object. Found ${Array.isArray(obj) ? 'array' : typeof obj}. | ||
'See https://github.com/typicode/json-server for example.`); | ||
} | ||
}; |
@@ -6,3 +6,2 @@ "use strict"; | ||
}; | ||
function getPage(array, page, perPage) { | ||
@@ -13,15 +12,11 @@ const obj = {}; | ||
obj.items = array.slice(start, end); | ||
if (obj.items.length === 0) { | ||
return obj; | ||
} | ||
if (page > 1) { | ||
obj.prev = page - 1; | ||
} | ||
if (end < array.length) { | ||
obj.next = page + 1; | ||
} | ||
if (obj.items.length !== array.length) { | ||
@@ -32,4 +27,3 @@ obj.current = page; | ||
} | ||
return obj; | ||
} |
{ | ||
"name": "json-server", | ||
"version": "0.17.1", | ||
"version": "0.17.4", | ||
"description": "Get a full fake REST API with zero coding in less than 30 seconds", | ||
@@ -13,3 +13,3 @@ "main": "./lib/server/index.js", | ||
"prepare": "husky install", | ||
"test": "npm run build && cross-env NODE_ENV=test jest && npm run lint", | ||
"test": "npm run build && cross-env NODE_ENV=test jest", | ||
"start": "babel-node -- src/cli/bin db.json -r routes.json", | ||
@@ -67,2 +67,3 @@ "lint": "eslint . --ignore-path .gitignore", | ||
"server-ready": "^0.3.1", | ||
"standard": "^17.1.0", | ||
"supertest": "^6.0.1", | ||
@@ -69,0 +70,0 @@ "temp-write": "^4.0.0" |
@@ -18,3 +18,3 @@ function ResourceItem({ name, length }) { | ||
length: Array.isArray(db[name]) && db[name].length, | ||
}) | ||
}), | ||
) | ||
@@ -44,3 +44,3 @@ .join('')} | ||
(db) => | ||
(document.getElementById('resources').innerHTML = ResourcesBlock({ db })) | ||
(document.getElementById('resources').innerHTML = ResourcesBlock({ db })), | ||
) | ||
@@ -61,3 +61,3 @@ | ||
<td><code>β’</code> ${customRoutes[rule]}</td> | ||
</tr>` | ||
</tr>`, | ||
) | ||
@@ -78,3 +78,3 @@ .join('')} | ||
customRoutes, | ||
})) | ||
})), | ||
) |
@@ -38,12 +38,4 @@ # JSON Server [![Node.js CI](https://github.com/typicode/json-server/actions/workflows/node.js.yml/badge.svg?branch=master)](https://github.com/typicode/json-server/actions/workflows/node.js.yml) | ||
<p align="center"> | ||
<a href="https://megafamous.com/buy-instagram-followers" target="_blank"> | ||
<img src="https://jsonplaceholder.typicode.com/megafamous.png" height="70px"> | ||
</a> | ||
</p> | ||
<p> </p> | ||
<p> </p> | ||
<h2 align="center">Silver sponsors π₯</h2> | ||
@@ -352,3 +344,3 @@ | ||
__Tip__ use modules like [Faker](https://github.com/Marak/faker.js), [Casual](https://github.com/boo1ean/casual), [Chance](https://github.com/victorquinn/chancejs) or [JSON Schema Faker](https://github.com/json-schema-faker/json-schema-faker). | ||
__Tip__ use modules like [Faker](https://github.com/faker-js/faker), [Casual](https://github.com/boo1ean/casual), [Chance](https://github.com/victorquinn/chancejs) or [JSON Schema Faker](https://github.com/json-schema-faker/json-schema-faker). | ||
@@ -368,3 +360,3 @@ ### HTTPS | ||
"/posts/:category": "/posts?category=:category", | ||
"/articles\\?id=:id": "/posts/:id" | ||
"/articles?id=:id": "/posts/:id" | ||
} | ||
@@ -371,0 +363,0 @@ ``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
58811
1151
25
634