function create() { return express().set('json spaces', 2); }
...
```sh
$ npm install json-server --save-dev
```
```js
// server.js
var jsonServer = require('json-server')
var server = jsonServer.create()
var router = jsonServer.router('db.json')
var middlewares = jsonServer.defaults()
server.use(middlewares)
server.use(router)
server.listen(3000, function () {
console.log('JSON Server is running')
...
defaults = function (opts) { var userDir = path.join(process.cwd(), 'public'); var defaultDir = path.join(__dirname, 'public'); var staticDir = fs.existsSync(userDir) ? userDir : defaultDir; opts = objectAssign({ logger: true, static: staticDir }, opts); var arr = []; // Compress all requests if (!opts.noGzip) { arr.push(compression()); } // Logger if (opts.logger) { arr.push(logger('dev', { skip: function skip(req) { return process.env.NODE_ENV === 'test' || req.path === '/favicon.ico'; } })); } // Enable CORS for all the requests, including static files if (!opts.noCors) { arr.push(cors({ origin: true, credentials: true })); } if (process.env.NODE_ENV === 'development') { // only use in development arr.push(errorhandler()); } // Serve static files arr.push(express.static(opts.static)); // No cache for IE // https://support.microsoft.com/en-us/kb/234067 arr.push(function (req, res, next) { res.header('Cache-Control', 'no-cache'); res.header('Pragma', 'no-cache'); res.header('Expires', '-1'); next(); }); // Read-only if (opts.readOnly) { arr.push(function (req, res, next) { if (req.method === 'GET') { next(); // Continue } else { res.sendStatus(403); // Forbidden } }); } return arr; }
...
```
```js
// server.js
var jsonServer = require('json-server')
var server = jsonServer.create()
var router = jsonServer.router('db.json')
var middlewares = jsonServer.defaults()
server.use(middlewares)
server.use(router)
server.listen(3000, function () {
console.log('JSON Server is running')
})
```
...
rewriter = function (routes) { var router = express.Router(); router.get('/__rules', function (req, res) { res.json(routes); }); Object.keys(routes).forEach(function (route) { if (route.indexOf(':') !== -1) { router.all(route, function (req, res, next) { // Rewrite target url using params var target = routes[route]; for (var param in req.params) { target = target.replace(':' + param, req.params[param]); } req.url = target; req.query = updateQueryString(req.query, req.url); next(); }); } else { router.all(route + '*', function (req, res, next) { // Rewrite url by replacing prefix req.url = req.url.replace(route, routes[route]); req.query = updateQueryString(req.query, req.url); next(); }); } }); return router; }
...
body: res.locals.data
})
}
```
#### Rewriter example
To add rewrite rules, use `jsonServer.rewriter()`:
```javascript
// Add this before server.use(router)
server.use(jsonServer.rewriter({
'/api/': '/',
'/blog/:resource/:id/show': '/:resource/:id'
}))
...
router = function (source) { // Create router var router = express.Router(); // Add middlewares router.use(methodOverride()); router.use(bodyParser); // Create database var db = void 0; if (_.isObject(source)) { db = low(); db.setState(source); } else { db = low(source, { storage: fileAsync }); } validateData(db.getState()); // Add lodash-id methods to db db._.mixin(lodashId); // Add specific mixins db._.mixin(mixins); // Expose database router.db = db; // Expose render router.render = function (req, res) { res.jsonp(res.locals.data); }; // GET /db router.get('/db', function (req, res) { res.jsonp(db.getState()); }); // Handle /:parent/:parentId/:resource router.use(nested()); // Create routes db.forEach(function (value, key) { if (_.isPlainObject(value)) { router.use('/' + key, singular(db, key)); return; } if (_.isArray(value)) { router.use('/' + key, plural(db, key)); return; } var msg = 'Type of "' + key + '" (' + (typeof value === 'undefined' ? 'undefined' : _typeof(value)) + ') ' + (_.isObject(source ) ? '' : 'in ' + source) + ' is not supported. ' + 'Use objects or arrays of objects.'; throw new Error(msg); }).value(); router.use(function (req, res) { if (!res.locals.data) { res.status(404); res.locals.data = {}; } router.render(req, res); }); router.use(function (err, req, res, next) { console.error(err.stack); res.status(500).send(err.stack); }); return router; }
...
$ npm install json-server --save-dev
```
```js
// server.js
var jsonServer = require('json-server')
var server = jsonServer.create()
var router = jsonServer.router('db.json')
var middlewares = jsonServer.defaults()
server.use(middlewares)
server.use(router)
server.listen(3000, function () {
console.log('JSON Server is running')
})
...
function jsonParser(req, res, next) { if (req._body) { debug('body already parsed') next() return } req.body = req.body || {} // skip requests without bodies if (!typeis.hasBody(req)) { debug('skip empty body') next() return } debug('content-type %j', req.headers['content-type']) // determine if request should be parsed if (!shouldParse(req)) { debug('skip parsing') next() return } // assert charset per RFC 7159 sec 8.1 var charset = getCharset(req) || 'utf-8' if (charset.substr(0, 4) !== 'utf-') { debug('invalid charset') next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', { charset: charset })) return } // read read(req, res, next, parse, debug, { encoding: charset, inflate: inflate, limit: limit, verify: verify }) }
n/a
function urlencodedParser(req, res, next) { if (req._body) { debug('body already parsed') next() return } req.body = req.body || {} // skip requests without bodies if (!typeis.hasBody(req)) { debug('skip empty body') next() return } debug('content-type %j', req.headers['content-type']) // determine if request should be parsed if (!shouldParse(req)) { debug('skip parsing') next() return } // assert charset var charset = getCharset(req) || 'utf-8' if (charset !== 'utf-8') { debug('invalid charset') next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', { charset: charset })) return } // read read(req, res, next, parse, debug, { debug: debug, encoding: charset, inflate: inflate, limit: limit, verify: verify }) }
n/a
function JS(s) { return !URL(s) && /\.js$/.test(s); }
...
json: true
};
request(opts, function (err, response) {
if (err) return cb(err);
cb(null, response.body);
});
} else if (is.JS(source)) {
// Clear cache
var filename = path.resolve(source);
delete require.cache[filename];
var dataFn = require(filename);
if (typeof dataFn !== 'function') {
throw new Error('The database is a JavaScript file but the export is not a function.');
...
function JSON(s) { return !URL(s) && /\.json$/.test(s); }
...
function createApp(source, object, routes, middlewares, argv) {
var app = jsonServer.create();
var router = void 0;
try {
router = jsonServer.router(is.JSON(source) ? source : object);
} catch (e) {
console.log();
console.error(chalk.red(e.message.replace(/^/gm, ' ')));
process.exit(1);
}
var defaultsOpts = {
...
function URL(s) { return (/^(http|https):/.test(s) ); }
...
if (argv.watch) {
(function () {
console.log(chalk.gray(' Watching...'));
console.log();
var source = argv._[0];
// 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
var watchedDir = path.dirname(source);
var readError = false;
fs.watch(watchedDir, function (event, file) {
// https://github.com/typicode/json-server/issues/420
...
function createId(coll) { var _ = this; var idProperty = _.__id(); if (_.isEmpty(coll)) { return 1; } else { var id = _(coll).maxBy(idProperty)[idProperty]; // Increment integer id or generate string id return _.isFinite(id) ? ++id : shortid.generate(); } }
n/a
function deepQuery(value, q) { var _ = this; if (value && q) { if (_.isArray(value)) { for (var i = 0; i < value.length; i++) { if (_.deepQuery(value[i], q)) { return true; } } } else if (_.isObject(value) && !_.isArray(value)) { for (var k in value) { if (_.deepQuery(value[k], q)) { return true; } } } else if (value.toString().toLowerCase().indexOf(q) !== -1) { return true; } } }
...
}
function deepQuery(value, q) {
var _ = this;
if (value && q) {
if (_.isArray(value)) {
for (var i = 0; i < value.length; i++) {
if (_.deepQuery(value[i], q)) {
return true;
}
}
} else if (_.isObject(value) && !_.isArray(value)) {
for (var k in value) {
if (_.deepQuery(value[k], q)) {
return true;
...
function getRemovable(db) { var _ = this; var removable = []; _.each(db, function (coll, collName) { _.each(coll, function (doc) { _.each(doc, function (value, key) { if (/Id$/.test(key)) { var refName = pluralize.plural(key.slice(0, -2)); // Test if table exists if (db[refName]) { // Test if references is defined in table var ref = _.getById(db[refName], value); if (_.isUndefined(ref)) { removable.push({ name: collName, id: doc.id }); } } } }); }); }); return removable; }
...
}
// DELETE /name/:id
function destroy(req, res, next) {
var resource = db.get(name).removeById(req.params.id).value();
// Remove dependents documents
var removable = db._.getRemovable(db.getState());
removable.forEach(function (item) {
db.get(item.name).removeById(item.id).value();
});
if (resource) {
res.locals.data = {};
...
function getPage(array, page, perPage) { var obj = {}; var start = (page - 1) * perPage; var end = page * perPage; 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) { obj.current = page; obj.first = 1; obj.last = Math.ceil(array.length / perPage); } return obj; }
...
res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count' + (_page ? ', Link' : ''));
}
if (_page) {
_page = parseInt(_page, 10);
_page = _page >= 1 ? _page : 1;
_limit = parseInt(_limit, 10) || 10;
var page = utils.getPage(chain.value(), _page, _limit);
var links = {};
var fullURL = getFullURL(req);
if (page.first) {
links.first = fullURL.replace('page=' + page.current, 'page=' + page.first);
}
...