From 459ddf583430f3b19bcc4dc40ceffef7180ca591 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sat, 10 Sep 2016 15:25:53 +0200
Subject: [PATCH 001/494] Add pagination
---
 README.md | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index e44c61217..b1ebfaaff 100644
--- a/README.md
+++ b/README.md
@@ -85,16 +85,16 @@ GET /posts?id=1&id=2
 GET /comments?author.name=typicode
 ```
 
-### Slice
+### Paginate
 
-Add `_start` and `_end` or `_limit` (an `X-Total-Count` header is included in the response)
+Add `_page` and in the `Link` header you'll get `first`, `prev`, `next` and `last` links
 
 ```
-GET /posts?_start=20&_end=30
-GET /posts/1/comments?_start=20&_end=30
-GET /posts/1/comments?_start=20&_limit=10
+GET /posts?_page=7
 ```
 
+_10 items are returned by default_
+
 ### Sort
 
 Add `_sort` and `_order` (ascending order by default)
@@ -104,6 +104,16 @@ GET /posts?_sort=views&_order=DESC
 GET /posts/1/comments?_sort=votes&_order=ASC
 ```
 
+### Slice
+
+Add `_start` and `_end` or `_limit` (an `X-Total-Count` header is included in the response)
+
+```
+GET /posts?_start=20&_end=30
+GET /posts/1/comments?_start=20&_end=30
+GET /posts/1/comments?_start=20&_limit=10
+```
+
 ### Operators
 
 Add `_gte` or `_lte` for getting a range
From 2879dceec2ec0302af4c66db30846cedb72da302 Mon Sep 17 00:00:00 2001
From: Eduard Kyvenko 
Date: Mon, 12 Sep 2016 08:58:47 +0200
Subject: [PATCH 002/494] Fixed the issue with watching under Win10 with Cygwin
 (#356)
---
 src/cli/run.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cli/run.js b/src/cli/run.js
index d61f0ad92..975fbce93 100644
--- a/src/cli/run.js
+++ b/src/cli/run.js
@@ -168,7 +168,7 @@ module.exports = function (argv) {
       chokidar
         .watch(path.dirname(source))
         .on('change', function (file) {
-          if (file === source) {
+          if (path.resolve(file) === path.resolve(source)) {
             if (is.JSON(file)) {
               var obj = JSON.parse(fs.readFileSync(file))
               // Compare .json file content with in memory database
From 49704957975dd4094466d8448a8d8edad9eb8dc4 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 12 Sep 2016 09:05:59 +0200
Subject: [PATCH 003/494] Update CHANGELOG.md
---
 CHANGELOG.md | 5 +++++
 1 file changed, 5 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7800542e6..330c2de25 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Change Log
 
+## [0.8.20][2016-09-12]
+
+* Fix [#355](https://github.com/typicode/json-server/issues/355)
+* Add `_page` support
+
 ## [0.8.19][2016-08-18]
 
 * Fix [#341](https://github.com/typicode/json-server/issues/341)
From 250739b8d6b6dfd49225af1ba583ae137553edaa Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 12 Sep 2016 09:06:24 +0200
Subject: [PATCH 004/494] 0.8.20
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 85d540b73..19315fdd1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.8.19",
+  "version": "0.8.20",
   "description": "Serves JSON files through REST routes.",
   "main": "./src/server/index.js",
   "bin": "./bin/index.js",
From 26cda0ddf8c7c393e60c8abd1ba6014edb4b5d5c Mon Sep 17 00:00:00 2001
From: Attila Egyed 
Date: Tue, 13 Sep 2016 21:57:30 +0200
Subject: [PATCH 005/494] fix body parser (#338)
---
 src/server/defaults.js     | 4 ++++
 src/server/router/index.js | 3 ---
 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/server/defaults.js b/src/server/defaults.js
index cedd843af..219bbfb4e 100644
--- a/src/server/defaults.js
+++ b/src/server/defaults.js
@@ -2,6 +2,7 @@ var fs = require('fs')
 var path = require('path')
 var express = require('express')
 var logger = require('morgan')
+var bodyParser = require('body-parser')
 var cors = require('cors')
 var compression = require('compression')
 var errorhandler = require('errorhandler')
@@ -18,6 +19,9 @@ module.exports = function (opts) {
 
   var arr = []
 
+  arr.push(bodyParser.json({limit: '10mb', extended: false}))
+  arr.push(bodyParser.urlencoded({extended: false}))
+
   // Compress all requests
   if (!opts.noGzip) {
     arr.push(compression())
diff --git a/src/server/router/index.js b/src/server/router/index.js
index 657f6e5ea..0345aff95 100644
--- a/src/server/router/index.js
+++ b/src/server/router/index.js
@@ -1,6 +1,5 @@
 var express = require('express')
 var methodOverride = require('method-override')
-var bodyParser = require('body-parser')
 var _ = require('lodash')
 var _db = require('underscore-db')
 var low = require('lowdb')
@@ -15,8 +14,6 @@ module.exports = function (source) {
   var router = express.Router()
 
   // Add middlewares
-  router.use(bodyParser.json({limit: '10mb', extended: false}))
-  router.use(bodyParser.urlencoded({extended: false}))
   router.use(methodOverride())
 
   // Create database
From af36b78ced94c91ad5e7fb55a16432a57a9ff4be Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 13 Sep 2016 22:06:15 +0200
Subject: [PATCH 006/494] Move router middlewares to defaults
---
 src/server/defaults.js     | 10 ++++++----
 src/server/router/index.js |  4 ----
 2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/src/server/defaults.js b/src/server/defaults.js
index 219bbfb4e..fc1b7ec15 100644
--- a/src/server/defaults.js
+++ b/src/server/defaults.js
@@ -2,10 +2,11 @@ var fs = require('fs')
 var path = require('path')
 var express = require('express')
 var logger = require('morgan')
-var bodyParser = require('body-parser')
 var cors = require('cors')
 var compression = require('compression')
 var errorhandler = require('errorhandler')
+var bodyParser = require('body-parser')
+var methodOverride = require('method-override')
 var objectAssign = require('object-assign')
 
 module.exports = function (opts) {
@@ -19,9 +20,6 @@ module.exports = function (opts) {
 
   var arr = []
 
-  arr.push(bodyParser.json({limit: '10mb', extended: false}))
-  arr.push(bodyParser.urlencoded({extended: false}))
-
   // Compress all requests
   if (!opts.noGzip) {
     arr.push(compression())
@@ -70,5 +68,9 @@ module.exports = function (opts) {
     })
   }
 
+  arr.push(bodyParser.json({limit: '10mb', extended: false}))
+  arr.push(bodyParser.urlencoded({extended: false}))
+  arr.push(methodOverride())
+
   return arr
 }
diff --git a/src/server/router/index.js b/src/server/router/index.js
index 0345aff95..24d9edac4 100644
--- a/src/server/router/index.js
+++ b/src/server/router/index.js
@@ -1,5 +1,4 @@
 var express = require('express')
-var methodOverride = require('method-override')
 var _ = require('lodash')
 var _db = require('underscore-db')
 var low = require('lowdb')
@@ -13,9 +12,6 @@ module.exports = function (source) {
   // Create router
   var router = express.Router()
 
-  // Add middlewares
-  router.use(methodOverride())
-
   // Create database
   var db
   if (_.isObject(source)) {
From 0cafa450143963093b41377cbdf7457cbcb93686 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 13 Sep 2016 22:12:22 +0200
Subject: [PATCH 007/494] Update CHANGELOG.md
---
 CHANGELOG.md | 4 ++++
 1 file changed, 4 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 330c2de25..b0d00d129 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Change Log
 
+## [0.8.21][2016-09-13]
+
+* Fix bodyParser issue when using custom routes
+
 ## [0.8.20][2016-09-12]
 
 * Fix [#355](https://github.com/typicode/json-server/issues/355)
From 732c3305748aa4b6c4839d97f67526c241bbcad9 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 13 Sep 2016 22:17:09 +0200
Subject: [PATCH 008/494] Add common middlewares for defaults and router
---
 src/server/common.js       | 9 +++++++++
 src/server/defaults.js     | 9 ++-------
 src/server/router/index.js | 4 ++++
 3 files changed, 15 insertions(+), 7 deletions(-)
 create mode 100644 src/server/common.js
diff --git a/src/server/common.js b/src/server/common.js
new file mode 100644
index 000000000..26577f02d
--- /dev/null
+++ b/src/server/common.js
@@ -0,0 +1,9 @@
+var bodyParser = require('body-parser')
+var methodOverride = require('method-override')
+
+// common middlewares used in ./defaults.js and ./router/index.js
+module.exports = [
+  bodyParser.json({limit: '10mb', extended: false}),
+  bodyParser.urlencoded({extended: false}),
+  methodOverride()
+]
diff --git a/src/server/defaults.js b/src/server/defaults.js
index fc1b7ec15..6cbd60645 100644
--- a/src/server/defaults.js
+++ b/src/server/defaults.js
@@ -5,9 +5,8 @@ var logger = require('morgan')
 var cors = require('cors')
 var compression = require('compression')
 var errorhandler = require('errorhandler')
-var bodyParser = require('body-parser')
-var methodOverride = require('method-override')
 var objectAssign = require('object-assign')
+var common = require('./common')
 
 module.exports = function (opts) {
   var userDir = path.join(process.cwd(), 'public')
@@ -68,9 +67,5 @@ module.exports = function (opts) {
     })
   }
 
-  arr.push(bodyParser.json({limit: '10mb', extended: false}))
-  arr.push(bodyParser.urlencoded({extended: false}))
-  arr.push(methodOverride())
-
-  return arr
+  return arr.concat(common)
 }
diff --git a/src/server/router/index.js b/src/server/router/index.js
index 24d9edac4..481d00a38 100644
--- a/src/server/router/index.js
+++ b/src/server/router/index.js
@@ -7,11 +7,15 @@ var plural = require('./plural')
 var nested = require('./nested')
 var singular = require('./singular')
 var mixins = require('../mixins')
+var common = require('../common')
 
 module.exports = function (source) {
   // Create router
   var router = express.Router()
 
+  // Add middlewares
+  router.use(common)
+
   // Create database
   var db
   if (_.isObject(source)) {
From e5473811b16ad6e783628d239d946cba406ac02f Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 13 Sep 2016 22:18:53 +0200
Subject: [PATCH 009/494] 0.8.21
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 19315fdd1..1f4e563e2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.8.20",
+  "version": "0.8.21",
   "description": "Serves JSON files through REST routes.",
   "main": "./src/server/index.js",
   "bin": "./bin/index.js",
From b06bc27d91ea8a5fef5feb5825cf9d6252c39f6a Mon Sep 17 00:00:00 2001
From: Ashley L Hill 
Date: Fri, 30 Sep 2016 20:25:13 -0400
Subject: [PATCH 010/494] Add support for query params in rewrite targets
 (#373)
* Add support for query params in rewrite targets
Re-parse the rewrite target to add query params, fixes #372
* Use lodash for Object.assign for node v0.12 compatibility
---
 src/server/rewriter.js |  6 ++++++
 test/server/plural.js  | 10 +++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/server/rewriter.js b/src/server/rewriter.js
index e61cc4b95..3549c32a2 100644
--- a/src/server/rewriter.js
+++ b/src/server/rewriter.js
@@ -1,4 +1,6 @@
 var express = require('express')
+var url = require('url')
+var _ = require('lodash')
 
 module.exports = function (routes) {
   var router = express.Router()
@@ -12,6 +14,10 @@ module.exports = function (routes) {
           target = target.replace(':' + param, req.params[param])
         }
         req.url = target
+        if (target.indexOf('?')) {
+          // create query from target
+          _.assign(req.query, url.parse(target, true).query)
+        }
         next()
       })
     } else {
diff --git a/test/server/plural.js b/test/server/plural.js
index cf55b24c0..dbbcf39f4 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -74,7 +74,8 @@ describe('Server', function () {
     server.use(jsonServer.defaults())
     server.use(jsonServer.rewriter({
       '/api/': '/',
-      '/blog/posts/:id/show': '/posts/:id'
+      '/blog/posts/:id/show': '/posts/:id',
+      '/comments/special/:userId-:body': '/comments/?userId=:userId&body=:body'
     }))
     server.use(router)
   })
@@ -647,6 +648,13 @@ describe('Server', function () {
         .expect(db.posts[0])
         .end(done)
     })
+
+    it('should rewrite using params and query', function (done) {
+      request(server)
+        .get('/comments/special/1-quux')
+        .expect([db.comments[4]])
+        .end(done)
+    })
   })
 
   describe('router.render', function (done) {
From 86db19aa9490f1901107b34ecfdbd6a5bf86a0f8 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sat, 1 Oct 2016 17:00:45 +0200
Subject: [PATCH 011/494] Update README.md
---
 README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index b1ebfaaff..890bf3b45 100644
--- a/README.md
+++ b/README.md
@@ -184,7 +184,7 @@ GET /
 ### Static file server
 
 You can use JSON Server to serve your HTML, JS and CSS, simply create a `./public` directory
-or use `--static`.
+or use `--static` to set a different static files directory.
 
 ```bash
 mkdir public
@@ -193,7 +193,7 @@ json-server db.json
 ```
 
 ```bash
-json-server db.json --static ./static
+json-server db.json --static ./some-other-dir
 ```
 
 ### Alternative port
From b070d5619435bf78d49fc883b58e72b1485d7ed4 Mon Sep 17 00:00:00 2001
From: Alex Ciobica 
Date: Tue, 4 Oct 2016 13:04:48 +0300
Subject: [PATCH 012/494] Expose the Links header. (#381)
---
 src/server/router/plural.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/server/router/plural.js b/src/server/router/plural.js
index e59228eed..4d8d2c0ae 100644
--- a/src/server/router/plural.js
+++ b/src/server/router/plural.js
@@ -153,7 +153,7 @@ module.exports = function (db, name) {
     // Slice result
     if (_end || _limit || _page) {
       res.setHeader('X-Total-Count', chain.size())
-      res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count')
+      res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count' + (_page ? ', Links' : ''))
     }
 
     if (_page) {
From b44a0d8288611609a93dd4a04c5ec8f38197bb7d Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 4 Oct 2016 12:41:43 +0200
Subject: [PATCH 013/494] add Links header test
---
 test/server/plural.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/server/plural.js b/test/server/plural.js
index dbbcf39f4..b747155cb 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -261,7 +261,7 @@ describe('Server', function () {
         .get('/list?_page=2')
         .expect('Content-Type', /json/)
         .expect('x-total-count', db.list.length.toString())
-        .expect('Access-Control-Expose-Headers', 'X-Total-Count')
+        .expect('Access-Control-Expose-Headers', 'X-Total-Count, Links')
         .expect(db.list.slice(10, 20))
         .expect(200, done)
     })
@@ -281,7 +281,7 @@ describe('Server', function () {
         .expect('Content-Type', /json/)
         .expect('x-total-count', db.list.length.toString())
         .expect('link', link)
-        .expect('Access-Control-Expose-Headers', 'X-Total-Count')
+        .expect('Access-Control-Expose-Headers', 'X-Total-Count, Links')
         .expect(db.list.slice(1, 2))
         .expect(200, done)
     })
From d873d6f9537ae11e105ebf01b721c60b84acbbc5 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 4 Oct 2016 12:43:35 +0200
Subject: [PATCH 014/494] Update CHANGELOG.md
---
 CHANGELOG.md | 5 +++++
 1 file changed, 5 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b0d00d129..56c0b769e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Change Log
 
+## [0.8.22][2016-10-04]
+
+* Fix `Links` header issue when using `_page`
+* Add query params support to the route rewriter
+
 ## [0.8.21][2016-09-13]
 
 * Fix bodyParser issue when using custom routes
From d1fcca9efa106604b56865eb5fead3db1a2a1b65 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 4 Oct 2016 12:43:52 +0200
Subject: [PATCH 015/494] 0.8.22
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 1f4e563e2..8db4b769c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.8.21",
+  "version": "0.8.22",
   "description": "Serves JSON files through REST routes.",
   "main": "./src/server/index.js",
   "bin": "./bin/index.js",
From a7784f07f090202140ce9243944fae65bfc17cdd Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 6 Oct 2016 01:02:07 +0200
Subject: [PATCH 016/494] Update README.md
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 890bf3b45..bb70667de 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# JSON Server [](https://travis-ci.org/typicode/json-server) [](http://badge.fury.io/js/json-server) [](https://gitter.im/typicode/json-server?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+# JSON Server [](https://travis-ci.org/typicode/json-server) [](http://badge.fury.io/js/json-server) [](https://gitter.im/typicode/json-server?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
 Get a full fake REST API with __zero coding__ in __less than 30 seconds__ (seriously)
 
From 8f484cd7c0735291ad183eefb7d7aaf244cd7242 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 11 Oct 2016 10:43:49 +0200
Subject: [PATCH 017/494] Update README.md
Thanks to @istommao
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index bb70667de..77d366233 100644
--- a/README.md
+++ b/README.md
@@ -271,7 +271,7 @@ You can add your middlewares from the CLI using `--middlewares` option:
 ```js
 // first.js
 module.exports = function (req, res, next) {
-  res.Header('X-Hello', 'World')
+  res.header('X-Hello', 'World')
 }
 ```
 
From fddd4507057029bf0ee741e63b744862034caf25 Mon Sep 17 00:00:00 2001
From: mbaer3000 
Date: Thu, 13 Oct 2016 11:42:15 +0200
Subject: [PATCH 018/494] fix middlewares example (#385)
---
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 77d366233..1270880a2 100644
--- a/README.md
+++ b/README.md
@@ -269,9 +269,10 @@ Now you can access resources using additional routes.
 You can add your middlewares from the CLI using `--middlewares` option:
 
 ```js
-// first.js
+// hello.js
 module.exports = function (req, res, next) {
   res.header('X-Hello', 'World')
+  next()
 }
 ```
 
From 7a619bcc7b62fdd437102c247e0a8cb908f3e506 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 25 Oct 2016 21:42:36 +0200
Subject: [PATCH 019/494] Update README.md
---
 README.md | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 1270880a2..27cf3f4dd 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,8 @@ Also when doing requests, its good to know that
 $ npm install -g json-server
 ```
 
+__Beta__ if you want to try `v0.9.0-beta` [[README](https://github.com/typicode/json-server/tree/next)], you can use the following command `npm install -g json-server@next` 
+
 ## Routes
 
 Based on the previous `db.json` file, here are all the default routes. You can also add [other routes](#add-routes) using `--routes`.
From 0dbb5ba1a79a94b4248ed2c8501ffd74f66726e7 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sun, 30 Oct 2016 13:29:28 +0100
Subject: [PATCH 020/494] Update README.md
---
 README.md | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 27cf3f4dd..5652de895 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,15 @@ Also when doing requests, its good to know that
 $ npm install -g json-server
 ```
 
-__Beta__ if you want to try `v0.9.0-beta` [[README](https://github.com/typicode/json-server/tree/next)], you can use the following command `npm install -g json-server@next` 
+### Beta
+
+To try [v0.9.0-beta](https://github.com/typicode/json-server/tree/next)
+
+```bash
+$ npm install -g json-server@next
+```
+
+
 
 ## Routes
 
From 2b93bf5113aa2d2e1a36449613e3e8c7ec4eb13a Mon Sep 17 00:00:00 2001
From: Vahid Panjganj 
Date: Wed, 2 Nov 2016 22:33:55 +0000
Subject: [PATCH 021/494] Exposing `Link` in the header instead of `Links`
 (#394)
- fix the small typo `Links` to `Link`
- update relevant tests
---
 src/server/router/plural.js | 2 +-
 test/server/plural.js       | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/server/router/plural.js b/src/server/router/plural.js
index 4d8d2c0ae..2b7d266b1 100644
--- a/src/server/router/plural.js
+++ b/src/server/router/plural.js
@@ -153,7 +153,7 @@ module.exports = function (db, name) {
     // Slice result
     if (_end || _limit || _page) {
       res.setHeader('X-Total-Count', chain.size())
-      res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count' + (_page ? ', Links' : ''))
+      res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count' + (_page ? ', Link' : ''))
     }
 
     if (_page) {
diff --git a/test/server/plural.js b/test/server/plural.js
index b747155cb..7bddd09db 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -261,7 +261,7 @@ describe('Server', function () {
         .get('/list?_page=2')
         .expect('Content-Type', /json/)
         .expect('x-total-count', db.list.length.toString())
-        .expect('Access-Control-Expose-Headers', 'X-Total-Count, Links')
+        .expect('Access-Control-Expose-Headers', 'X-Total-Count, Link')
         .expect(db.list.slice(10, 20))
         .expect(200, done)
     })
@@ -281,7 +281,7 @@ describe('Server', function () {
         .expect('Content-Type', /json/)
         .expect('x-total-count', db.list.length.toString())
         .expect('link', link)
-        .expect('Access-Control-Expose-Headers', 'X-Total-Count, Links')
+        .expect('Access-Control-Expose-Headers', 'X-Total-Count, Link')
         .expect(db.list.slice(1, 2))
         .expect(200, done)
     })
From 1f89edb6656f2a414c195c1266f06b04e7a562ca Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 3 Nov 2016 09:17:41 +0100
Subject: [PATCH 022/494] Update CHANGELOG
---
 CHANGELOG.md | 4 ++++
 1 file changed, 4 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56c0b769e..a5ade0086 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Change Log
 
+## [0.8.23][2016-11-31]
+
+* Fix `Links` header
+
 ## [0.8.22][2016-10-04]
 
 * Fix `Links` header issue when using `_page`
From c6d0a572026cc95da0485b747a11f012b2d5081d Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 3 Nov 2016 09:19:26 +0100
Subject: [PATCH 023/494] Update CHANGELOG.md
---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5ade0086..b1ad26c7a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
 # Change Log
 
-## [0.8.23][2016-11-31]
+## [0.8.23][2016-11-03]
 
 * Fix `Links` header
 
From b2228581c8fdbf15b09a8a5f4139125e6fe9355e Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 3 Nov 2016 09:23:57 +0100
Subject: [PATCH 024/494] 0.8.23
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 8db4b769c..f0f2f896a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.8.22",
+  "version": "0.8.23",
   "description": "Serves JSON files through REST routes.",
   "main": "./src/server/index.js",
   "bin": "./bin/index.js",
From 0861dfe581a65c8cd0154d47b3ce9542cf0fc71e Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 3 Nov 2016 12:48:52 +0100
Subject: [PATCH 025/494] Update .travis.yml
---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index e986bdd0f..29d5864eb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,4 +2,4 @@ sudo: false
 language: node_js
 node_js:
   - "stable"
-  - "0.12"
+#  - "0.12"
From 44bdfb490a986e9666abc2c4da5acd2b61b053cc Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 10 Nov 2016 12:57:48 +0100
Subject: [PATCH 026/494] Update README.md
---
 README.md | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5652de895..28bcc58db 100644
--- a/README.md
+++ b/README.md
@@ -354,7 +354,15 @@ server.listen(3000, function () {
 $ node server.js
 ```
 
-For an in-memory database, you can pass an object to `jsonServer.router()`.
+The path you provide to the `jsonServer.router` function  is relative to the directory from where you launch your node process. If you run the above code from another directory, it’s better to use an absolute path:
+
+```js
+var path = require('path')
+var router = jsonServer.router(path.join(__dirname, 'db.json'))
+```
+
+For an in-memory database, simply pass an object to `jsonServer.router()`.
+
 Please note also that `jsonServer.router()` can be used in existing Express projects.
 
 #### Custom routes example
From 2b26630ac6379fba77eb104b22e83b41a004b52e Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sat, 12 Nov 2016 01:59:43 +0100
Subject: [PATCH 027/494] v0.9.0 (#404)
* Remove automatic type conversion
* Remove body-parser from default middlewares
* Ignore lib
* ES2015
* Use shortid
* Add babel-register
* Update paths to ./lib
* Add .npmignore
* Update bin
* temp fix
* Fix bin
* Add message when creating default db
* Use fs.watch
* Fix operator existence test
* Fix 0.12 tests
* Update dependencies
* Update
* Increase timeout
* Fix 0.12 support
* 0.9.0-beta.1
* Fix missing example.json issue
* 0.9.0-beta.2
* Update message
* Update CHANGELOG.md
* Update lowdb dependency
* Add error message
* Update README.md
* Add database validation
* Update
* Update
* Fix tests
* Update
---
 .babelrc                           |   2 +-
 .gitignore                         |   1 +
 .npmignore                         |   1 +
 CHANGELOG.md                       |  12 +
 README.md                          |  31 ++-
 bin/index.js                       |   2 +-
 package.json                       |  42 ++--
 src/cli/bin.js                     |   1 +
 src/cli/example.json               |   9 +
 src/cli/index.js                   |  12 +-
 src/cli/run.js                     | 138 +++++-----
 src/cli/utils/is.js                |  16 +-
 src/cli/utils/load.js              |  31 ++-
 src/server/body-parser.js          |   6 +
 src/server/common.js               |   9 -
 src/server/defaults.js             |  43 ++--
 src/server/index.js                |  11 +-
 src/server/mixins.js               |  51 ++--
 src/server/rewriter.js             |  20 +-
 src/server/router/index.js         |  60 ++---
 src/server/router/nested.js        |  21 +-
 src/server/router/plural.js        | 165 ++++++------
 src/server/router/singular.js      |   6 +-
 src/server/router/validate-data.js |  26 ++
 src/server/utils.js                |  24 +-
 test/cli/index.js                  | 253 ++++++++++---------
 test/mocha.opts                    |   3 +
 test/server/mixins.js              |  66 +++--
 test/server/plural.js              | 388 +++++++++++++++--------------
 test/server/singular.js            |  15 +-
 test/server/utils.js               |  28 +--
 test/server/validate-data.js       |  24 ++
 32 files changed, 828 insertions(+), 689 deletions(-)
 create mode 100644 .npmignore
 create mode 100644 src/cli/bin.js
 create mode 100644 src/cli/example.json
 create mode 100644 src/server/body-parser.js
 delete mode 100644 src/server/common.js
 create mode 100644 src/server/router/validate-data.js
 create mode 100644 test/mocha.opts
 create mode 100644 test/server/validate-data.js
diff --git a/.babelrc b/.babelrc
index 3c078e9f9..45001da4a 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,5 +1,5 @@
 {
   "presets": [
-    "es2015"
+    ["es2015", { "loose": true }]
   ]
 }
diff --git a/.gitignore b/.gitignore
index 835d515cb..0c475f8ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 **/*.log
 node_modules
 tmp
+lib
 .DS_Store
 .idea
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 000000000..e8310385c
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1 @@
+src
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1ad26c7a..1b4cbfdd8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
 # Change Log
 
+## [0.9.0][2016-11-11]
+
+* Shorter `uuid`
+* No automatic conversion of strings to boolean or integer
+* Create a default `db.json` file if it doesn't exist
+* Fix
+  * [#361](https://github.com/typicode/json-server/issues/361)
+  * [#363](https://github.com/typicode/json-server/issues/363) [#365](https://github.com/typicode/json-server/issues/365)
+  * [#374](https://github.com/typicode/json-server/issues/374)
+  * [#383](https://github.com/typicode/json-server/issues/383)
+* Updated dependencies and codebase to ES6 
+
 ## [0.8.23][2016-11-03]
 
 * Fix `Links` header
diff --git a/README.md b/README.md
index 28bcc58db..37c7db91a 100644
--- a/README.md
+++ b/README.md
@@ -97,10 +97,14 @@ GET /comments?author.name=typicode
 
 ### Paginate
 
-Add `_page` and in the `Link` header you'll get `first`, `prev`, `next` and `last` links
+Use `_page` and optionally `_limit` to paginate returned data.
+
+In the `Link` header you'll get `first`, `prev`, `next` and `last` links.
+
 
 ```
 GET /posts?_page=7
+GET /posts?_page=7&_limit=20
 ```
 
 _10 items are returned by default_
@@ -247,16 +251,21 @@ module.exports = function() {
 $ json-server index.js
 ```
 
-__Tip__ use modules like [faker](https://github.com/Marak/faker.js), [casual](https://github.com/boo1ean/casual) or [chance](https://github.com/victorquinn/chancejs).
+__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).
+
+### HTTPS
 
-### Add routes
+There's many way to set up SSL in development. One simple way though is to use [hotel](https://github.com/typicode/hotel).
 
-Create a `routes.json` file. Pay attention to start every route with /.
+### Add custom routes
+
+Create a `routes.json` file. Pay attention to start every route with `/`.
 
 ```json
 {
   "/api/": "/",
-  "/blog/:resource/:id/show": "/:resource/:id"
+  "/blog/:resource/:id/show": "/:resource/:id",
+  "/blog/:category": "/posts/:id?category=:category"
 }
 ```
 
@@ -268,10 +277,11 @@ json-server db.json --routes routes.json
 
 Now you can access resources using additional routes.
 
-```bash
-/api/posts
-/api/posts/1
-/blog/posts/1/show
+```sh
+/api/posts # → /posts
+/api/posts/1  # → /posts/1
+/blog/posts/1/show # → /posts/1
+/blog/javascript # → /posts?category=javascript
 ```
 
 ### Add middlewares
@@ -383,6 +393,9 @@ server.get('/echo', function (req, res) {
   res.jsonp(req.query)
 })
 
+// To handle POST, PUT and PATCH you need to use a body-parser
+// You can use the one used by JSON Server
+server.use(jsonServer.bodyParser)
 server.use(function (req, res, next) {
   if (req.method === 'POST') {
     req.body.createdAt = Date.now()
diff --git a/bin/index.js b/bin/index.js
index 633765557..af3551aa9 100755
--- a/bin/index.js
+++ b/bin/index.js
@@ -1,2 +1,2 @@
 #!/usr/bin/env node
-require('../src/cli')()
+require('../lib/cli/bin')
diff --git a/package.json b/package.json
index f0f2f896a..9bab48524 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
   "name": "json-server",
-  "version": "0.8.23",
+  "version": "0.9.0-beta.2",
   "description": "Serves JSON files through REST routes.",
-  "main": "./src/server/index.js",
+  "main": "./lib/server/index.js",
   "bin": "./bin/index.js",
   "directories": {
     "test": "test"
@@ -10,46 +10,46 @@
   "dependencies": {
     "body-parser": "^1.15.2",
     "chalk": "^1.1.3",
-    "chokidar": "^1.6.0",
     "compression": "^1.6.0",
     "connect-pause": "^0.1.0",
     "cors": "^2.3.0",
     "errorhandler": "^1.2.0",
     "express": "^4.9.5",
     "lodash": "^4.11.2",
-    "lowdb": "^0.13.1",
+    "lowdb": "^0.14.0",
     "method-override": "^2.1.2",
     "morgan": "^1.3.1",
-    "node-uuid": "^1.4.2",
     "object-assign": "^4.0.1",
     "pluralize": "^3.0.0",
     "request": "^2.72.0",
     "server-destroy": "^1.0.1",
-    "underscore-db": "^0.10.0",
+    "shortid": "^2.2.6",
+    "underscore-db": "^0.12.0",
     "update-notifier": "^1.0.2",
-    "yargs": "^4.2.0"
+    "yargs": "^6.0.0"
   },
   "devDependencies": {
     "babel-cli": "^6.10.1",
-    "babel-preset-es2015": "^6.9.0",
-    "cross-env": "^1.0.8",
+    "babel-preset-es2015": "^6.16.0",
+    "babel-register": "^6.16.3",
+    "cross-env": "^2.0.1",
     "husky": "^0.11.4",
     "mkdirp": "^0.5.1",
-    "mocha": "^2.2.4",
+    "mocha": "^3.1.2",
     "os-tmpdir": "^1.0.1",
     "rimraf": "^2.5.2",
-    "server-ready": "^0.2.0",
-    "standard": "^7.1.2",
-    "supertest": "^1.2.0",
+    "server-ready": "^0.3.1",
+    "standard": "^8.3.0",
+    "supertest": "^2.0.0",
     "temp-write": "^2.1.0"
   },
   "scripts": {
-    "test": "npm run test:cli && npm run test:server && standard",
-    "test:cli": "cross-env NODE_ENV=test mocha -R spec test/cli/*.js",
-    "test:server": "cross-env NODE_ENV=test mocha -R spec test/server/*.js",
+    "test": "npm run test:cli && npm run test:server && standard --fix",
+    "test:cli": "npm run build && cross-env NODE_ENV=test mocha test/cli/*.js",
+    "test:server": "cross-env NODE_ENV=test mocha test/server/*.js",
     "start": "node bin",
     "prepush": "npm t",
-    "build": "babel src -d lib"
+    "build": "babel src -d lib --copy-files"
   },
   "repository": {
     "type": "git",
@@ -76,5 +76,11 @@
   "bugs": {
     "url": "https://github.com/typicode/json-server/issues"
   },
-  "homepage": "https://github.com/typicode/json-server"
+  "homepage": "https://github.com/typicode/json-server",
+  "standard": {
+    "fix": true,
+    "env": {
+      "mocha": true
+    }
+  }
 }
diff --git a/src/cli/bin.js b/src/cli/bin.js
new file mode 100644
index 000000000..2b8efefce
--- /dev/null
+++ b/src/cli/bin.js
@@ -0,0 +1 @@
+require('./')()
diff --git a/src/cli/example.json b/src/cli/example.json
new file mode 100644
index 000000000..4d3941aea
--- /dev/null
+++ b/src/cli/example.json
@@ -0,0 +1,9 @@
+{
+  "posts": [
+    { "id": 1, "title": "json-server", "author": "typicode" }
+  ],
+  "comments": [
+    { "id": 1, "body": "some comment", "postId": 1 }
+  ],
+  "profile": { "name": "typicode" }
+}
\ No newline at end of file
diff --git a/src/cli/index.js b/src/cli/index.js
index 29c7f719e..8f62da1b9 100644
--- a/src/cli/index.js
+++ b/src/cli/index.js
@@ -1,12 +1,12 @@
-var updateNotifier = require('update-notifier')
-var yargs = require('yargs')
-var run = require('./run')
-var pkg = require('../../package.json')
+const updateNotifier = require('update-notifier')
+const yargs = require('yargs')
+const run = require('./run')
+const pkg = require('../../package.json')
 
 module.exports = function () {
-  updateNotifier({ pkg: pkg }).notify()
+  updateNotifier({ pkg }).notify()
 
-  var argv = yargs
+  const argv = yargs
     .config('config')
     .usage('$0 [options] ')
     .options({
diff --git a/src/cli/run.js b/src/cli/run.js
index 975fbce93..648974c2d 100644
--- a/src/cli/run.js
+++ b/src/cli/run.js
@@ -1,22 +1,22 @@
-var fs = require('fs')
-var path = require('path')
-var _ = require('lodash')
-var chalk = require('chalk')
-var chokidar = require('chokidar')
-var enableDestroy = require('server-destroy')
-var pause = require('connect-pause')
-var is = require('./utils/is')
-var load = require('./utils/load')
-var jsonServer = require('../server')
+const fs = require('fs')
+const path = require('path')
+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 example = require('./example.json')
+const jsonServer = require('../server')
 
 function prettyPrint (argv, object, rules) {
-  var host = argv.host === '0.0.0.0' ? 'localhost' : argv.host
-  var port = argv.port
-  var root = 'http://' + host + ':' + port
+  const host = argv.host === '0.0.0.0' ? 'localhost' : argv.host
+  const port = argv.port
+  const root = `http://${host}:${port}`
 
   console.log()
   console.log(chalk.bold('  Resources'))
-  for (var prop in object) {
+  for (let prop in object) {
     console.log('  ' + root + '/' + prop)
   }
 
@@ -35,15 +35,23 @@ function prettyPrint (argv, object, rules) {
 }
 
 function createApp (source, object, routes, middlewares, argv) {
-  var app = jsonServer.create()
+  const app = jsonServer.create()
 
-  var router = jsonServer.router(
-    is.JSON(source)
-    ? source
-    : object
-  )
+  let router
 
-  var defaultsOpts = {
+  try {
+    router = jsonServer.router(
+      is.JSON(source)
+      ? source
+      : object
+    )
+  } catch (e) {
+    console.log()
+    console.error(chalk.red(e.message.replace(/^/gm, '  ')))
+    process.exit(1)
+  }
+
+  const defaultsOpts = {
     logger: !argv.quiet,
     readOnly: argv.readOnly,
     noCors: argv.noCors,
@@ -54,11 +62,11 @@ function createApp (source, object, routes, middlewares, argv) {
     defaultsOpts.static = path.join(process.cwd(), argv.static)
   }
 
-  var defaults = jsonServer.defaults(defaultsOpts)
+  const defaults = jsonServer.defaults(defaultsOpts)
   app.use(defaults)
 
   if (routes) {
-    var rewriter = jsonServer.rewriter(routes)
+    const rewriter = jsonServer.rewriter(routes)
     app.use(rewriter)
   }
 
@@ -78,18 +86,18 @@ function createApp (source, object, routes, middlewares, argv) {
 }
 
 module.exports = function (argv) {
-  var source = argv._[0]
-  var app
-  var server
+  const source = argv._[0]
+  let app
+  let server
 
   if (!fs.existsSync(argv.snapshots)) {
-    console.log('Error: snapshots directory ' + argv.snapshots + ' doesn\'t exist')
+    console.log(`Error: snapshots directory ${argv.snapshots} doesn't exist`)
     process.exit(1)
   }
 
   // noop log fn
   if (argv.quiet) {
-    console.log = function () {}
+    console.log = () => {}
   }
 
   console.log()
@@ -97,20 +105,30 @@ module.exports = function (argv) {
 
   function start (cb) {
     console.log()
+
+    // Be nice and create a default db.json if it doesn't exist
+    if (is.JSON(source) && !fs.existsSync(source)) {
+      console.log(chalk.yellow(`  Oops, ${source} doesn't seem to exist`))
+      console.log(chalk.yellow(`  Creating ${source} with some default data`))
+      console.log()
+      fs.writeFileSync(source, JSON.stringify(example, null, 2))
+    }
+
     console.log(chalk.gray('  Loading', source))
 
     // Load JSON, JS or HTTP database
-    load(source, function (err, data) {
+    load(source, (err, data) => {
       if (err) throw err
 
       // Load additional routes
+      let routes
       if (argv.routes) {
         console.log(chalk.gray('  Loading', argv.routes))
-        var routes = JSON.parse(fs.readFileSync(argv.routes))
+        routes = JSON.parse(fs.readFileSync(argv.routes))
       }
 
       // Load middlewares
-      var middlewares
+      let middlewares
       if (argv.middlewares) {
         middlewares = argv.middlewares.map(function (m) {
           console.log(chalk.gray('  Loading', m))
@@ -136,7 +154,7 @@ module.exports = function (argv) {
   }
 
   // Start server
-  start(function () {
+  start(() => {
     // Snapshot
     console.log(
       chalk.gray('  Type s + enter at any time to create a snapshot of the database')
@@ -144,13 +162,13 @@ module.exports = function (argv) {
 
     process.stdin.resume()
     process.stdin.setEncoding('utf8')
-    process.stdin.on('data', function (chunk) {
+    process.stdin.on('data', (chunk) => {
       if (chunk.trim().toLowerCase() === 's') {
-        var filename = 'db-' + Date.now() + '.json'
-        var file = path.join(argv.snapshots, filename)
-        var state = app.db.getState()
+        const filename = 'db-' + Date.now() + '.json'
+        const file = path.join(argv.snapshots, filename)
+        const state = app.db.getState()
         fs.writeFileSync(file, JSON.stringify(state, null, 2), 'utf-8')
-        console.log('  Saved snapshot to ' + path.relative(process.cwd(), file) + '\n')
+        console.log(`  Saved snapshot to ${path.relative(process.cwd(), file)}\n`)
       }
     })
 
@@ -158,43 +176,45 @@ module.exports = function (argv) {
     if (argv.watch) {
       console.log(chalk.gray('  Watching...'))
       console.log()
-      var source = argv._[0]
+      const 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
-      chokidar
-        .watch(path.dirname(source))
-        .on('change', function (file) {
-          if (path.resolve(file) === path.resolve(source)) {
-            if (is.JSON(file)) {
-              var obj = JSON.parse(fs.readFileSync(file))
-              // Compare .json file content with in memory database
-              var isDatabaseDifferent = !_.isEqual(obj, app.db.getState())
-              if (isDatabaseDifferent) {
-                console.log(chalk.gray('  ' + file + ' has changed, reloading...'))
-                server && server.destroy()
-                start()
-              }
-            } else {
-              console.log(chalk.gray('  ' + file + ' has changed, reloading...'))
+      const watchedDir = path.dirname(source)
+      fs.watch(watchedDir, (event, file) => {
+        const watchedFile = path.resolve(watchedDir, file)
+        if (watchedFile === path.resolve(source)) {
+          if (is.JSON(watchedFile)) {
+            var obj = JSON.parse(fs.readFileSync(watchedFile))
+            // Compare .json file content with in memory database
+            var isDatabaseDifferent = !_.isEqual(obj, app.db.getState())
+            if (isDatabaseDifferent) {
+              console.log(chalk.gray(`  ${source} has changed, reloading...`))
               server && server.destroy()
               start()
             }
+          } else {
+            console.log(chalk.gray(`  ${source} has changed, reloading...`))
+            server && server.destroy()
+            start()
           }
-        })
+        }
+      })
 
       // Watch routes
       if (argv.routes) {
-        chokidar
-          .watch(argv.routes)
-          .on('change', function (file) {
-            console.log(chalk.gray('  ' + file + ' has changed, reloading...'))
+        const watchedDir = path.dirname(argv.routes)
+        fs.watch(watchedDir, (event, file) => {
+          const watchedFile = path.resolve(watchedDir, file)
+          if (watchedFile === path.resolve(argv.routes)) {
+            console.log(chalk.gray(`  ${argv.routes} has changed, reloading...`))
             server && server.destroy()
             start()
-          })
+          }
+        })
       }
     }
   })
diff --git a/src/cli/utils/is.js b/src/cli/utils/is.js
index a59da210a..2f5b8dfd2 100644
--- a/src/cli/utils/is.js
+++ b/src/cli/utils/is.js
@@ -1,17 +1,17 @@
 module.exports = {
-  JSON: isJSON,
-  JS: isJS,
-  URL: isURL
+  JSON,
+  JS,
+  URL
 }
 
-function isJSON (s) {
-  return !isURL(s) && /\.json$/.test(s)
+function JSON (s) {
+  return !URL(s) && /\.json$/.test(s)
 }
 
-function isJS (s) {
-  return !isURL(s) && /\.js$/.test(s)
+function JS (s) {
+  return !URL(s) && /\.js$/.test(s)
 }
 
-function isURL (s) {
+function URL (s) {
   return /^(http|https):/.test(s)
 }
diff --git a/src/cli/utils/load.js b/src/cli/utils/load.js
index 28a1e94cb..e14a2a547 100644
--- a/src/cli/utils/load.js
+++ b/src/cli/utils/load.js
@@ -1,30 +1,37 @@
-var path = require('path')
-var request = require('request')
-var low = require('lowdb')
-var fileAsync = require('lowdb/lib/file-async')
-var is = require('./is')
+const path = require('path')
+const request = require('request')
+const low = require('lowdb')
+const fileAsync = require('lowdb/lib/file-async')
+const is = require('./is')
 
 module.exports = function (source, cb) {
-  var data
-
   if (is.URL(source)) {
-    request({ url: source, json: true }, function (err, response) {
+    // Load remote data
+    const opts = {
+      url: source,
+      json: true
+    }
+
+    request(opts, (err, response) => {
       if (err) return cb(err)
       cb(null, response.body)
     })
   } else if (is.JS(source)) {
-    var filename = path.resolve(source)
+    // Clear cache
+    const filename = path.resolve(source)
     delete require.cache[filename]
-    var dataFn = require(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.')
     }
 
-    data = dataFn()
+    // Run dataFn to generate data
+    const data = dataFn()
     cb(null, data)
   } else if (is.JSON(source)) {
-    data = low(source, { storage: fileAsync }).getState()
+    // Load JSON using lowdb
+    const data = low(source, { storage: fileAsync }).getState()
     cb(null, data)
   } else {
     throw new Error('Unsupported source ' + source)
diff --git a/src/server/body-parser.js b/src/server/body-parser.js
new file mode 100644
index 000000000..eeeda211e
--- /dev/null
+++ b/src/server/body-parser.js
@@ -0,0 +1,6 @@
+const bodyParser = require('body-parser')
+
+module.exports = [
+  bodyParser.json({limit: '10mb', extended: false}),
+  bodyParser.urlencoded({extended: false})
+]
diff --git a/src/server/common.js b/src/server/common.js
deleted file mode 100644
index 26577f02d..000000000
--- a/src/server/common.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var bodyParser = require('body-parser')
-var methodOverride = require('method-override')
-
-// common middlewares used in ./defaults.js and ./router/index.js
-module.exports = [
-  bodyParser.json({limit: '10mb', extended: false}),
-  bodyParser.urlencoded({extended: false}),
-  methodOverride()
-]
diff --git a/src/server/defaults.js b/src/server/defaults.js
index 6cbd60645..44265a389 100644
--- a/src/server/defaults.js
+++ b/src/server/defaults.js
@@ -1,23 +1,22 @@
-var fs = require('fs')
-var path = require('path')
-var express = require('express')
-var logger = require('morgan')
-var cors = require('cors')
-var compression = require('compression')
-var errorhandler = require('errorhandler')
-var objectAssign = require('object-assign')
-var common = require('./common')
+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 objectAssign = require('object-assign')
 
 module.exports = function (opts) {
-  var userDir = path.join(process.cwd(), 'public')
-  var defaultDir = path.join(__dirname, 'public')
-  var staticDir = fs.existsSync(userDir)
+  const userDir = path.join(process.cwd(), 'public')
+  const defaultDir = path.join(__dirname, 'public')
+  const staticDir = fs.existsSync(userDir)
     ? userDir
     : defaultDir
 
   opts = objectAssign({ logger: true, static: staticDir }, opts)
 
-  var arr = []
+  const arr = []
 
   // Compress all requests
   if (!opts.noGzip) {
@@ -26,12 +25,14 @@ module.exports = function (opts) {
 
   // Logger
   if (opts.logger) {
-    arr.push(logger('dev', {
-      skip: function (req, res) {
-        return process.env.NODE_ENV === 'test' ||
+    arr.push(
+      logger('dev', {
+        skip: (req) => (
+          process.env.NODE_ENV === 'test' ||
           req.path === '/favicon.ico'
-      }
-    }))
+        )
+      })
+    )
   }
 
   // Enable CORS for all the requests, including static files
@@ -49,7 +50,7 @@ module.exports = function (opts) {
 
   // No cache for IE
   // https://support.microsoft.com/en-us/kb/234067
-  arr.push(function (req, res, next) {
+  arr.push((req, res, next) => {
     res.header('Cache-Control', 'no-cache')
     res.header('Pragma', 'no-cache')
     res.header('Expires', '-1')
@@ -58,7 +59,7 @@ module.exports = function (opts) {
 
   // Read-only
   if (opts.readOnly) {
-    arr.push(function (req, res, next) {
+    arr.push((req, res, next) => {
       if (req.method === 'GET') {
         next() // Continue
       } else {
@@ -67,5 +68,5 @@ module.exports = function (opts) {
     })
   }
 
-  return arr.concat(common)
+  return arr
 }
diff --git a/src/server/index.js b/src/server/index.js
index 9a74caf58..dd98979be 100644
--- a/src/server/index.js
+++ b/src/server/index.js
@@ -1,12 +1,9 @@
-var express = require('express')
+const express = require('express')
 
 module.exports = {
-  create: function () {
-    var server = express()
-    server.set('json spaces', 2)
-    return server
-  },
+  create: () => express().set('json spaces', 2),
   defaults: require('./defaults'),
   router: require('./router'),
-  rewriter: require('./rewriter')
+  rewriter: require('./rewriter'),
+  bodyParser: require('./body-parser')
 }
diff --git a/src/server/mixins.js b/src/server/mixins.js
index 43dab7f18..1f980df73 100644
--- a/src/server/mixins.js
+++ b/src/server/mixins.js
@@ -1,28 +1,28 @@
-var uuid = require('node-uuid')
-var pluralize = require('pluralize')
+const shortid = require('shortid')
+const pluralize = require('pluralize')
 
 module.exports = {
-  getRemovable: getRemovable,
-  createId: createId,
-  deepQuery: deepQuery
+  getRemovable,
+  createId,
+  deepQuery
 }
 
 // Returns document ids that have unsatisfied relations
 // Example: a comment that references a post that doesn't exist
 function getRemovable (db) {
-  var _ = this
-  var removable = []
-  _.each(db, function (coll, collName) {
-    _.each(coll, function (doc) {
-      _.each(doc, function (value, key) {
+  const _ = this
+  const removable = []
+  _.each(db, (coll, collName) => {
+    _.each(coll, (doc) => {
+      _.each(doc, (value, key) => {
         if (/Id$/.test(key)) {
-          var refName = pluralize.plural(key.slice(0, -2))
+          const 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)
+            const ref = _.getById(db[refName], value)
             if (_.isUndefined(ref)) {
-              removable.push({name: collName, id: doc.id})
+              removable.push({ name: collName, id: doc.id })
             }
           }
         }
@@ -36,36 +36,31 @@ function getRemovable (db) {
 // Return incremented id or uuid
 // Used to override underscore-db's createId with utils.createId
 function createId (coll) {
-  var _ = this
-  var idProperty = _.__id()
+  const _ = this
+  const idProperty = _.__id()
   if (_.isEmpty(coll)) {
     return 1
   } else {
-    var id = _.maxBy(coll, function (doc) {
-      return doc[idProperty]
-    })[idProperty]
+    let id = _(coll).maxBy(idProperty)[idProperty]
 
-    if (_.isFinite(id)) {
-      // Increment integer id
-      return ++id
-    } else {
-      // Generate string id
-      return uuid()
-    }
+    // Increment integer id or generate string id
+    return _.isFinite(id)
+      ? ++id
+      : shortid.generate()
   }
 }
 
 function deepQuery (value, q) {
-  var _ = this
+  const _ = this
   if (value && q) {
     if (_.isArray(value)) {
-      for (var i = 0; i < value.length; i++) {
+      for (let i = 0; i < value.length; i++) {
         if (_.deepQuery(value[i], q)) {
           return true
         }
       }
     } else if (_.isObject(value) && !_.isArray(value)) {
-      for (var k in value) {
+      for (let k in value) {
         if (_.deepQuery(value[k], q)) {
           return true
         }
diff --git a/src/server/rewriter.js b/src/server/rewriter.js
index 3549c32a2..718220f37 100644
--- a/src/server/rewriter.js
+++ b/src/server/rewriter.js
@@ -1,16 +1,16 @@
-var express = require('express')
-var url = require('url')
-var _ = require('lodash')
+const express = require('express')
+const url = require('url')
+const _ = require('lodash')
 
-module.exports = function (routes) {
-  var router = express.Router()
+module.exports = (routes) => {
+  const router = express.Router()
 
-  Object.keys(routes).forEach(function (route) {
+  Object.keys(routes).forEach((route) => {
     if (route.indexOf(':') !== -1) {
-      router.all(route, function (req, res, next) {
+      router.all(route, (req, res, next) => {
         // Rewrite target url using params
-        var target = routes[route]
-        for (var param in req.params) {
+        let target = routes[route]
+        for (let param in req.params) {
           target = target.replace(':' + param, req.params[param])
         }
         req.url = target
@@ -21,7 +21,7 @@ module.exports = function (routes) {
         next()
       })
     } else {
-      router.all(route + '*', function (req, res, next) {
+      router.all(route + '*', (req, res, next) => {
         // Rewrite url by replacing prefix
         req.url = req.url.replace(route, routes[route])
         next()
diff --git a/src/server/router/index.js b/src/server/router/index.js
index 481d00a38..7a7ad6eaf 100644
--- a/src/server/router/index.js
+++ b/src/server/router/index.js
@@ -1,23 +1,26 @@
-var express = require('express')
-var _ = require('lodash')
-var _db = require('underscore-db')
-var low = require('lowdb')
-var fileAsync = require('lowdb/lib/file-async')
-var plural = require('./plural')
-var nested = require('./nested')
-var singular = require('./singular')
-var mixins = require('../mixins')
-var common = require('../common')
-
-module.exports = function (source) {
+const express = require('express')
+const methodOverride = require('method-override')
+const _ = require('lodash')
+const _db = require('underscore-db')
+const low = require('lowdb')
+const fileAsync = require('lowdb/lib/file-async')
+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 = (source) => {
   // Create router
-  var router = express.Router()
+  const router = express.Router()
 
   // Add middlewares
-  router.use(common)
+  router.use(methodOverride())
+  router.use(bodyParser)
 
   // Create database
-  var db
+  let db
   if (_.isObject(source)) {
     db = low()
     db.setState(source)
@@ -25,6 +28,8 @@ module.exports = function (source) {
     db = low(source, { storage: fileAsync })
   }
 
+  validateData(db.getState())
+
   // Add underscore-db methods to db
   db._.mixin(_db)
 
@@ -35,40 +40,39 @@ module.exports = function (source) {
   router.db = db
 
   // Expose render
-  router.render = function (req, res) {
+  router.render = (req, res) => {
     res.jsonp(res.locals.data)
   }
 
   // GET /db
-  function showDatabase (req, res, next) {
+  router.get('/db', (req, res) => {
     res.jsonp(db.getState())
-  }
-
-  router.get('/db', showDatabase)
+  })
 
+  // Handle /:parent/:parentId/:resource
   router.use(nested())
 
   // Create routes
-  db.forEach(function (value, key) {
+  db.forEach((value, key) => {
     if (_.isPlainObject(value)) {
-      router.use('/' + key, singular(db, key))
+      router.use(`/${key}`, singular(db, key))
       return
     }
 
     if (_.isArray(value)) {
-      router.use('/' + key, plural(db, key))
+      router.use(`/${key}`, plural(db, key))
       return
     }
 
-    var msg =
-      'Type of "' + key + '" (' + typeof value + ') ' +
-      (_.isObject(source) ? '' : 'in ' + source) + ' is not supported. ' +
+    const msg =
+      `Type of "${key}" (${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) {
+  router.use((req, res) => {
     if (!res.locals.data) {
       res.status(404)
       res.locals.data = {}
@@ -77,7 +81,7 @@ module.exports = function (source) {
     router.render(req, res)
   })
 
-  router.use(function (err, req, res, next) {
+  router.use((err, req, res, next) => {
     console.error(err.stack)
     res.status(500).send(err.stack)
   })
diff --git a/src/server/router/nested.js b/src/server/router/nested.js
index a3edcc2e1..61a1a5926 100644
--- a/src/server/router/nested.js
+++ b/src/server/router/nested.js
@@ -1,23 +1,22 @@
-var express = require('express')
-var pluralize = require('pluralize')
-var utils = require('../utils')
+const express = require('express')
+const pluralize = require('pluralize')
 
-module.exports = function () {
-  var router = express.Router()
+module.exports = () => {
+  const router = express.Router()
 
   // Rewrite URL (/:resource/:id/:nested -> /:nested) and request query
   function get (req, res, next) {
-    var prop = pluralize.singular(req.params.resource)
-    req.query[prop + 'Id'] = utils.toNative(req.params.id)
-    req.url = '/' + req.params.nested
+    const prop = pluralize.singular(req.params.resource)
+    req.query[`${prop}Id`] = req.params.id
+    req.url = `/${req.params.nested}`
     next()
   }
 
   // Rewrite URL (/:resource/:id/:nested -> /:nested) and request body
   function post (req, res, next) {
-    var prop = pluralize.singular(req.params.resource)
-    req.body[prop + 'Id'] = utils.toNative(req.params.id)
-    req.url = '/' + req.params.nested
+    const prop = pluralize.singular(req.params.resource)
+    req.body[`${prop}Id`] = req.params.id
+    req.url = `/${req.params.nested}`
     next()
   }
 
diff --git a/src/server/router/plural.js b/src/server/router/plural.js
index 2b7d266b1..24ecf850c 100644
--- a/src/server/router/plural.js
+++ b/src/server/router/plural.js
@@ -1,20 +1,21 @@
-var express = require('express')
-var _ = require('lodash')
-var pluralize = require('pluralize')
-var utils = require('../utils')
+const url = require('url')
+const express = require('express')
+const _ = require('lodash')
+const pluralize = require('pluralize')
+const utils = require('../utils')
 
-module.exports = function (db, name) {
+module.exports = (db, name) => {
   // Create router
-  var router = express.Router()
+  const router = express.Router()
 
   // Embed function used in GET /name and GET /name/id
   function embed (resource, e) {
     e && [].concat(e)
-      .forEach(function (externalResource) {
+      .forEach((externalResource) => {
         if (db.get(externalResource).value) {
-          var query = {}
-          var singularResource = pluralize.singular(name)
-          query[singularResource + 'Id'] = resource.id
+          const query = {}
+          const singularResource = pluralize.singular(name)
+          query[`${singularResource}Id`] = resource.id
           resource[externalResource] = db.get(externalResource).filter(query).value()
         }
       })
@@ -23,17 +24,22 @@ module.exports = function (db, name) {
   // Expand function used in GET /name and GET /name/id
   function expand (resource, e) {
     e && [].concat(e)
-      .forEach(function (innerResource) {
-        var plural = pluralize(innerResource)
+      .forEach((innerResource) => {
+        const plural = pluralize(innerResource)
         if (db.get(plural).value()) {
-          var prop = innerResource + 'Id'
+          const prop = `${innerResource}Id`
           resource[innerResource] = db.get(plural).getById(resource[prop]).value()
         }
       })
   }
 
   function getFullURL (req) {
-    return req.protocol + '://' + req.get('host') + req.originalUrl
+    const root = url.format({
+      protocol: req.protocol,
+      host: req.get('host')
+    })
+
+    return `${root}${req.originalUrl}`
   }
 
   // GET /name
@@ -44,19 +50,19 @@ module.exports = function (db, name) {
   // GET /name?_embed=&_expand=
   function list (req, res, next) {
     // Resource chain
-    var chain = db.get(name)
+    let chain = db.get(name)
 
     // Remove q, _start, _end, ... from req.query to avoid filtering using those
     // parameters
-    var q = req.query.q
-    var _start = req.query._start
-    var _end = req.query._end
-    var _page = req.query._page
-    var _sort = req.query._sort
-    var _order = req.query._order
-    var _limit = req.query._limit
-    var _embed = req.query._embed
-    var _expand = req.query._expand
+    let q = req.query.q
+    let _start = req.query._start
+    let _end = req.query._end
+    let _page = req.query._page
+    let _sort = req.query._sort
+    let _order = req.query._order
+    let _limit = req.query._limit
+    let _embed = req.query._embed
+    let _expand = req.query._expand
     delete req.query.q
     delete req.query._start
     delete req.query._end
@@ -68,17 +74,17 @@ module.exports = function (db, name) {
 
     // Automatically delete query parameters that can't be found
     // in the database
-    Object.keys(req.query).forEach(function (query) {
-      var arr = db.get(name).value()
-      for (var i in arr) {
+    Object.keys(req.query).forEach((query) => {
+      const arr = db.get(name).value()
+      for (let i in arr) {
         if (
           _.has(arr[i], query) ||
           query === 'callback' ||
           query === '_' ||
-          query.indexOf('_lte') !== -1 ||
-          query.indexOf('_gte') !== -1 ||
-          query.indexOf('_ne') !== -1 ||
-          query.indexOf('_like') !== -1
+          /_lte$/.test(query) ||
+          /_gte$/.test(query) ||
+          /_ne$/.test(query) ||
+          /_like$/.test(query)
         ) return
       }
       delete req.query[query]
@@ -88,9 +94,9 @@ module.exports = function (db, name) {
       // Full-text search
       q = q.toLowerCase()
 
-      chain = chain.filter(function (obj) {
-        for (var key in obj) {
-          var value = obj[key]
+      chain = chain.filter((obj) => {
+        for (let key in obj) {
+          const value = obj[key]
           if (db._.deepQuery(value, q)) {
             return true
           }
@@ -98,41 +104,41 @@ module.exports = function (db, name) {
       })
     }
 
-    Object.keys(req.query).forEach(function (key) {
+    Object.keys(req.query).forEach((key) => {
       // Don't take into account JSONP query parameters
       // jQuery adds a '_' query parameter too
       if (key !== 'callback' && key !== '_') {
         // Always use an array, in case req.query is an array
-        var arr = [].concat(req.query[key])
+        const arr = [].concat(req.query[key])
 
-        chain = chain.filter(function (element) {
+        chain = chain.filter((element) => {
           return arr
-            .map(utils.toNative)
             .map(function (value) {
-              var isDifferent = key.indexOf('_ne') !== -1
-              var isRange = key.indexOf('_lte') !== -1 || key.indexOf('_gte') !== -1
-              var isLike = key.indexOf('_like') !== -1
-              var path = key.replace(/(_lte|_gte|_ne|_like)$/, '')
-              var elementValue = _.get(element, path)
+              const isDifferent = /_ne$/.test(key)
+              const isRange = /_lte$/.test(key) || /_gte$/.test(key)
+              const isLike = /_like$/.test(key)
+              const path = key.replace(/(_lte|_gte|_ne|_like)$/, '')
+              const elementValue = _.get(element, path)
+
+              if (!elementValue) {
+                return
+              }
 
               if (isRange) {
-                var isLowerThan = key.indexOf('_gte') !== -1
+                const isLowerThan = /_gte$/.test(key)
 
-                if (isLowerThan) {
-                  return value <= elementValue
-                } else {
-                  return value >= elementValue
-                }
+                return isLowerThan
+                  ? value <= elementValue
+                  : value >= elementValue
               } else if (isDifferent) {
-                return value !== elementValue
+                return value !== elementValue.toString()
               } else if (isLike) {
-                return new RegExp(value, 'i').test(elementValue)
+                return new RegExp(value, 'i').test(elementValue.toString())
               } else {
-                return _.matchesProperty(key, value)(element)
+                return value === elementValue.toString()
               }
-            }).reduce(function (a, b) {
-              return a || b
             })
+            .reduce((a, b) => a || b)
         })
       }
     })
@@ -160,9 +166,9 @@ module.exports = function (db, name) {
       _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)
+      const page = utils.getPage(chain.value(), _page, _limit)
+      const links = {}
+      const fullURL = getFullURL(req)
 
       if (page.first) {
         links.first = fullURL.replace('page=' + page.current, 'page=' + page.first)
@@ -207,24 +213,25 @@ module.exports = function (db, name) {
   // GET /name/:id
   // GET /name/:id?_embed=&_expand
   function show (req, res, next) {
-    var _embed = req.query._embed
-    var _expand = req.query._expand
-    var id = utils.toNative(req.params.id)
-    var resource = db.get(name).getById(id).value()
+    const _embed = req.query._embed
+    const _expand = req.query._expand
+    const resource = db.get(name)
+      .getById(req.params.id)
+      .value()
 
     if (resource) {
       // Clone resource to avoid making changes to the underlying object
-      resource = _.cloneDeep(resource)
+      const clone = _.cloneDeep(resource)
 
       // Embed other resources based on resource id
       // /posts/1?_embed=comments
-      embed(resource, _embed)
+      embed(clone, _embed)
 
       // Expand inner resources based on id
       // /posts/1?_expand=user
-      expand(resource, _expand)
+      expand(clone, _expand)
 
-      res.locals.data = resource
+      res.locals.data = clone
     }
 
     next()
@@ -232,11 +239,7 @@ module.exports = function (db, name) {
 
   // POST /name
   function create (req, res, next) {
-    for (var key in req.body) {
-      req.body[key] = utils.toNative(req.body[key])
-    }
-
-    var resource = db.get(name)
+    const resource = db.get(name)
       .insert(req.body)
       .value()
 
@@ -248,18 +251,14 @@ module.exports = function (db, name) {
   // PUT /name/:id
   // PATCH /name/:id
   function update (req, res, next) {
-    for (var key in req.body) {
-      req.body[key] = utils.toNative(req.body[key])
-    }
-
-    var id = utils.toNative(req.params.id)
-    var chain = db.get(name)
+    const id = req.params.id
+    let chain = db.get(name)
 
     chain = req.method === 'PATCH'
       ? chain.updateById(id, req.body)
       : chain.replaceById(id, req.body)
 
-    var resource = chain.value()
+    const resource = chain.value()
 
     if (resource) {
       res.locals.data = resource
@@ -270,13 +269,17 @@ module.exports = function (db, name) {
 
   // DELETE /name/:id
   function destroy (req, res, next) {
-    var resource = db.get(name).removeById(utils.toNative(req.params.id)).value()
+    const resource = db.get(name)
+      .removeById(req.params.id)
+      .value()
 
     // Remove dependents documents
-    var removable = db._.getRemovable(db.getState())
+    const removable = db._.getRemovable(db.getState())
 
-    _.each(removable, function (item) {
-      db.get(item.name).removeById(item.id).value()
+    removable.forEach((item) => {
+      db.get(item.name)
+        .removeById(item.id)
+        .value()
     })
 
     if (resource) {
diff --git a/src/server/router/singular.js b/src/server/router/singular.js
index c5c629198..f33bbda09 100644
--- a/src/server/router/singular.js
+++ b/src/server/router/singular.js
@@ -1,7 +1,7 @@
-var express = require('express')
+const express = require('express')
 
-module.exports = function (db, name) {
-  var router = express.Router()
+module.exports = (db, name) => {
+  const router = express.Router()
 
   function show (req, res, next) {
     res.locals.data = db.get(name).value()
diff --git a/src/server/router/validate-data.js b/src/server/router/validate-data.js
new file mode 100644
index 000000000..5bb5dbc1e
--- /dev/null
+++ b/src/server/router/validate-data.js
@@ -0,0 +1,26 @@
+const _ = require('lodash')
+
+function validateKey (key) {
+  if (key.indexOf('/') !== -1) {
+    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/tree/next#add-custom-routes'
+    ].join('\n')
+    throw new Error(msg)
+  }
+}
+
+module.exports = (obj) => {
+  if (_.isPlainObject(obj)) {
+    Object
+      .keys(obj)
+      .forEach(validateKey)
+  } else {
+    throw new Error(
+      `Data must be an object. Found ${typeof obj}.` +
+      'See https://github.com/typicode/json-server for example.'
+    )
+  }
+}
diff --git a/src/server/utils.js b/src/server/utils.js
index 8f8307a96..f7a5c9a50 100644
--- a/src/server/utils.js
+++ b/src/server/utils.js
@@ -1,27 +1,5 @@
 module.exports = {
-  toNative: toNative,
-  getPage: getPage
-}
-
-// Turns string to native.
-// Example:
-//   'true' -> true
-//   '1' -> 1
-function toNative (value) {
-  if (typeof value === 'string') {
-    if (
-      value === '' ||
-      value.trim() !== value ||
-      (value.length > 1 && value[0] === '0')
-    ) {
-      return value
-    } else if (value === 'true' || value === 'false') {
-      return value === 'true'
-    } else if (!isNaN(+value)) {
-      return +value
-    }
-  }
-  return value
+  getPage
 }
 
 function getPage (array, page, perPage) {
diff --git a/test/cli/index.js b/test/cli/index.js
index ce9657c48..f822f6d61 100644
--- a/test/cli/index.js
+++ b/test/cli/index.js
@@ -1,70 +1,73 @@
-var fs = require('fs')
-var path = require('path')
-var cp = require('child_process')
-var assert = require('assert')
-var supertest = require('supertest')
-var osTmpdir = require('os-tmpdir')
-var tempWrite = require('temp-write')
-var mkdirp = require('mkdirp')
-var rimraf = require('rimraf')
-var express = require('express')
-var serverReady = require('server-ready')
-var pkg = require('../../package.json')
-
-var PORT = 3100
+const fs = require('fs')
+const path = require('path')
+const cp = require('child_process')
+const assert = require('assert')
+const supertest = require('supertest')
+const osTmpdir = require('os-tmpdir')
+const tempWrite = require('temp-write')
+const mkdirp = require('mkdirp')
+const rimraf = require('rimraf')
+const express = require('express')
+const serverReady = require('server-ready')
+
+let PORT = 3100
+
+const middlewareFiles = {
+  en: './fixtures/middlewares/en.js',
+  jp: './fixtures/middlewares/jp.js'
+}
+
+const bin = path.join(__dirname, '../../lib/cli/bin')
 
 function cli (args) {
-  var bin = path.join(__dirname, '../..', pkg.bin)
-  return cp.spawn('node', [bin, '-p', PORT].concat(args), {
+  return cp.spawn('node', ['--', bin, '-p', PORT].concat(args), {
     cwd: __dirname,
     stdio: ['pipe', process.stdout, process.stderr]
   })
 }
 
-/* global beforeEach, afterEach, describe, it */
-
-describe('cli', function () {
-  var child
-  var request
-  var dbFile
-  var routesFile
-  var middlewareFiles = {
-    en: './fixtures/middlewares/en.js',
-    jp: './fixtures/middlewares/jp.js'
-  }
-
-  beforeEach(function () {
-    dbFile = tempWrite.sync(JSON.stringify({
-      posts: [
-        { id: 1 },
-        { _id: 2 }
-      ]
-    }), 'db.json')
-
-    routesFile = tempWrite.sync(JSON.stringify({
-      '/blog/': '/'
-    }), 'routes.json')
+describe('cli', () => {
+  let child
+  let request
+  let dbFile
+  let routesFile
+
+  beforeEach(() => {
+    dbFile = tempWrite.sync(
+      JSON.stringify({
+        posts: [
+          { id: 1 },
+          { _id: 2 }
+        ]
+      }),
+      'db.json'
+    )
+
+    routesFile = tempWrite.sync(
+      JSON.stringify({ '/blog/': '/' }),
+      'routes.json'
+    )
 
     ++PORT
-    request = supertest('http://localhost/' + PORT)
+    request = supertest(`http://localhost:${PORT}`)
   })
 
-  afterEach(function () {
-    child.kill()
+  afterEach(() => {
+    child.kill('SIGKILL')
   })
 
-  describe('db.json', function () {
-    beforeEach(function (done) {
-      child = cli([dbFile])
+  describe('db.json', () => {
+    beforeEach((done) => {
+      child = cli([ dbFile ])
       serverReady(PORT, done)
     })
 
-    it('should support JSON file', function (done) {
+    it('should support JSON file', (done) => {
       request.get('/posts').expect(200, done)
     })
 
-    it('should send CORS headers', function (done) {
-      var origin = 'http://example.com/'
+    it('should send CORS headers', (done) => {
+      const origin = 'http://example.com/'
 
       request.get('/posts')
         .set('Origin', origin)
@@ -72,12 +75,12 @@ describe('cli', function () {
         .expect(200, done)
     })
 
-    it('should update JSON file', function (done) {
+    it('should update JSON file', (done) => {
       request.post('/posts')
         .send({ title: 'hello' })
-        .end(function () {
-          setTimeout(function () {
-            var str = fs.readFileSync(dbFile, 'utf8')
+        .end(() => {
+          setTimeout(() => {
+            const str = fs.readFileSync(dbFile, 'utf8')
             assert(str.indexOf('hello') !== -1)
             done()
           }, 1000)
@@ -85,118 +88,122 @@ describe('cli', function () {
     })
   })
 
-  describe('seed.js', function () {
-    beforeEach(function (done) {
-      child = cli(['fixtures/seed.js'])
+  describe('seed.js', () => {
+    beforeEach((done) => {
+      child = cli([ 'fixtures/seed.js' ])
       serverReady(PORT, done)
     })
 
-    it('should support JS file', function (done) {
+    it('should support JS file', (done) => {
       request.get('/posts').expect(200, done)
     })
   })
 
-  describe('http://localhost:8080/db', function () {
-    beforeEach(function (done) {
-      var fakeServer = express()
-      fakeServer.get('/db', function (req, res) {
+  describe('http://localhost:8080/db', () => {
+    beforeEach((done) => {
+      const fakeServer = express()
+      fakeServer.get('/db', (req, res) => {
         res.jsonp({ posts: [] })
       })
-      fakeServer.listen(8080, function () {
-        child = cli(['http://localhost:8080/db'])
+      fakeServer.listen(8080, () => {
+        child = cli([ 'http://localhost:8080/db' ])
         serverReady(PORT, done)
       })
     })
 
-    it('should support URL file', function (done) {
+    it('should support URL file', (done) => {
       request.get('/posts').expect(200, done)
     })
   })
 
-  describe('db.json -r routes.json -m middleware.js -i _id --read-only', function () {
-    beforeEach(function (done) {
-      child = cli([dbFile, '-r', routesFile, '-m', middlewareFiles.en, '-i', '_id', '--read-only'])
+  describe('db.json -r routes.json -m middleware.js -i _id --read-only', () => {
+    beforeEach((done) => {
+      child = cli([ dbFile, '-r', routesFile, '-m', middlewareFiles.en, '-i', '_id', '--read-only' ])
       serverReady(PORT, done)
     })
 
-    it('should use routes.json and _id as the identifier', function (done) {
+    it('should use routes.json and _id as the identifier', (done) => {
       request.get('/blog/posts/2').expect(200, done)
     })
 
-    it('should apply middlewares', function (done) {
+    it('should apply middlewares', (done) => {
       request.get('/blog/posts/2').expect('X-Hello', 'World', done)
     })
 
-    it('should allow only GET requests', function (done) {
+    it('should allow only GET requests', (done) => {
       request.post('/blog/posts').expect(403, done)
     })
   })
 
-  describe('db.json -m first-middleware.js second-middleware.js', function () {
-    beforeEach(function (done) {
-      child = cli([dbFile, '-m', middlewareFiles.en, middlewareFiles.jp])
+  describe('db.json -m first-middleware.js second-middleware.js', () => {
+    beforeEach((done) => {
+      child = cli([ dbFile, '-m', middlewareFiles.en, middlewareFiles.jp ])
       serverReady(PORT, done)
     })
 
-    it('should apply all middlewares', function (done) {
+    it('should apply all middlewares', (done) => {
       request.get('/posts')
         .expect('X-Hello', 'World')
         .expect('X-Konnichiwa', 'Sekai', done)
     })
   })
 
-  describe('db.json -d 1000', function () {
-    beforeEach(function (done) {
-      child = cli([dbFile, '-d', 1000])
+  describe('db.json -d 1000', () => {
+    beforeEach((done) => {
+      child = cli([ dbFile, '-d', 1000 ])
       serverReady(PORT, done)
     })
 
-    it('should delay response', function (done) {
-      var start = new Date()
+    it('should delay response', (done) => {
+      const start = new Date()
       request.get('/posts').expect(200, function (err) {
-        var end = new Date()
-        done(end - start > 1000 ? err : new Error('Request wasn\'t delayed'))
+        const end = new Date()
+        done(
+          end - start > 1000
+          ? err
+          : new Error('Request wasn\'t delayed')
+        )
       })
     })
   })
 
-  describe('db.json -s fixtures/public -S /some/path/snapshots', function () {
-    var snapshotsDir = path.join(osTmpdir(), 'snapshots')
-    var publicDir = 'fixtures/public'
+  describe('db.json -s fixtures/public -S /some/path/snapshots', () => {
+    const snapshotsDir = path.join(osTmpdir(), 'snapshots')
+    const publicDir = 'fixtures/public'
 
-    beforeEach(function (done) {
+    beforeEach((done) => {
       rimraf.sync(snapshotsDir)
       mkdirp.sync(snapshotsDir)
 
-      child = cli([dbFile, '-s', publicDir, '-S', snapshotsDir])
-      serverReady(PORT, function () {
+      child = cli([ dbFile, '-s', publicDir, '-S', snapshotsDir ])
+      serverReady(PORT, () => {
         child.stdin.write('s\n')
         setTimeout(done, 100)
       })
     })
 
-    it('should serve fixtures/public', function (done) {
+    it('should serve fixtures/public', (done) => {
       request.get('/').expect(/Hello/, done)
     })
 
-    it('should save a snapshot in snapshots dir', function () {
+    it('should save a snapshot in snapshots dir', () => {
       assert.equal(fs.readdirSync(snapshotsDir).length, 1)
     })
   })
 
-  describe('fixtures/seed.json --no-cors=true', function () {
-    beforeEach(function (done) {
-      child = cli(['fixtures/seed.js', '--no-cors=true'])
+  describe('fixtures/seed.json --no-cors=true', () => {
+    beforeEach((done) => {
+      child = cli([ 'fixtures/seed.js', '--no-cors=true' ])
       serverReady(PORT, done)
     })
 
-    it('should not send Access-Control-Allow-Origin headers', function (done) {
-      var origin = 'http://example.com/'
+    it('should not send Access-Control-Allow-Origin headers', (done) => {
+      const origin = 'http://example.com/'
 
       request.get('/posts')
         .set('Origin', origin)
         .expect(200)
-        .end(function (err, res) {
+        .end((err, res) => {
           if (err) {
             done(err)
           } if ('access-control-allow-origin' in res.headers) {
@@ -208,13 +215,13 @@ describe('cli', function () {
     })
   })
 
-  describe('fixtures/seed.json --no-gzip=true', function () {
-    beforeEach(function (done) {
-      child = cli(['fixtures/seed.js', '--no-gzip=true'])
+  describe('fixtures/seed.json --no-gzip=true', () => {
+    beforeEach((done) => {
+      child = cli([ 'fixtures/seed.js', '--no-gzip=true' ])
       serverReady(PORT, done)
     })
 
-    it('should not set Content-Encoding to gzip', function (done) {
+    it('should not set Content-Encoding to gzip', (done) => {
       request.get('/posts')
         .expect(200)
         .end(function (err, res) {
@@ -229,39 +236,55 @@ describe('cli', function () {
     })
   })
 
-  describe('--watch db.json -r routes.json', function () {
-    beforeEach(function (done) {
-      child = cli(['--watch', dbFile, '-r', routesFile])
+  describe('--watch db.json -r routes.json', () => {
+    beforeEach((done) => {
+      child = cli([ dbFile, '-r', routesFile, '--watch' ])
       serverReady(PORT, done)
     })
 
-    it('should watch db file', function (done) {
+    it('should watch db file', (done) => {
       fs.writeFileSync(dbFile, JSON.stringify({ foo: [] }))
-      setTimeout(function () {
+      setTimeout(() => {
         request.get('/foo').expect(200, done)
       }, 1000)
     })
 
-    it('should watch routes file', function (done) {
-      // Can be very slow
-      this.timeout(10000)
+    it('should watch routes file', (done) => {
       fs.writeFileSync(routesFile, JSON.stringify({ '/api/': '/' }))
-      setTimeout(function () {
+      setTimeout(() => {
         request.get('/api/posts').expect(200, done)
-      }, 9000)
+      }, 1000)
     })
   })
 
-  describe('db.json --config some-config.json', function (done) {
-    beforeEach(function (done) {
-      child = cli([dbFile, '--config', 'fixtures/config.json'])
+  describe('non existent db.json', () => {
+    beforeEach((done) => {
+      fs.unlinkSync(dbFile)
+      child = cli([ dbFile ])
       serverReady(PORT, done)
     })
 
-    it('should apply all middlewares', function (done) {
-      request.get('/posts')
-        .expect('X-Hello', 'World')
-        .expect('X-Konnichiwa', 'Sekai', done)
+    it('should create JSON file if it doesn\'t exist', (done) => {
+      request.get('/posts').expect(200, done)
+    })
+  })
+
+  describe('db.json with error', () => {
+    beforeEach(() => {
+      dbFile = tempWrite.sync(
+        JSON.stringify({ 'a/b': [] }),
+        'db-error.json'
+      )
+    })
+
+    it('should exit with an error', (done) => {
+      child = cli([ dbFile ])
+      child.on('exit', (code) => {
+        if (code === 1) {
+          return done()
+        }
+        return done(new Error('should exit with error code'))
+      })
     })
   })
 })
diff --git a/test/mocha.opts b/test/mocha.opts
new file mode 100644
index 000000000..82a4ddb26
--- /dev/null
+++ b/test/mocha.opts
@@ -0,0 +1,3 @@
+--compilers js:babel-register
+--reporter spec
+--timeout 5000
\ No newline at end of file
diff --git a/test/server/mixins.js b/test/server/mixins.js
index 395230085..8707fd0c0 100644
--- a/test/server/mixins.js
+++ b/test/server/mixins.js
@@ -1,34 +1,52 @@
-var assert = require('assert')
-var _ = require('lodash')
-var _db = require('underscore-db')
-var mixins = require('../../src/server/mixins')
+const assert = require('assert')
+const _ = require('lodash')
+const _db = require('underscore-db')
+const mixins = require('../../src/server/mixins')
 
-/* global describe, it */
+describe('mixins', () => {
+  let db
 
-describe('mixins', function () {
-  describe('getRemovable', function () {
-    it('should return removable documents', function () {
-      var db = {
-        posts: [
-          {id: 1, comment: 1}
-        ],
-        comments: [
-          {id: 1, postId: 1},
-          // Comments below references a post that doesn't exist
-          {id: 2, postId: 2},
-          {id: 3, postId: 2}
-        ]
-      }
+  before(() => {
+    _.mixin(_db)
+    _.mixin(mixins)
+  })
 
-      var expected = [
-        {name: 'comments', id: 2},
-        {name: 'comments', id: 3}
+  beforeEach(() => {
+    db = {
+      posts: [
+        { id: 1, comment: 1 }
+      ],
+      comments: [
+        { id: 1, postId: 1 },
+        // Comments below references a post that doesn't exist
+        { id: 2, postId: 2 },
+        { id: 3, postId: 2 }
+      ],
+      photos: [
+        { id: '1' },
+        { id: '2' }
       ]
+    }
+  })
 
-      _.mixin(_db)
-      _.mixin(mixins)
+  describe('getRemovable', () => {
+    it('should return removable documents', () => {
+      const expected = [
+        { name: 'comments', id: 2 },
+        { name: 'comments', id: 3 }
+      ]
 
       assert.deepEqual(_.getRemovable(db), expected)
     })
   })
+
+  describe('createId', () => {
+    it('should return a new id', () => {
+      assert.equal(_.createId(db.comments), 4)
+    })
+
+    it('should return a new uuid', () => {
+      assert.notEqual(_.createId(db.photos), 3)
+    })
+  })
 })
diff --git a/test/server/plural.js b/test/server/plural.js
index 7bddd09db..1cd47748c 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -1,43 +1,46 @@
-var assert = require('assert')
-var _ = require('lodash')
-var request = require('supertest')
-var jsonServer = require('../../src/server')
-
-/* global beforeEach, describe, it */
-describe('Server', function () {
-  var server
-  var router
-  var db
-
-  beforeEach(function () {
+const assert = require('assert')
+const _ = require('lodash')
+const request = require('supertest')
+const jsonServer = require('../../src/server')
+
+describe('Server', () => {
+  let server
+  let router
+  let db
+
+  beforeEach(() => {
     db = {}
 
     db.posts = [
-      {id: 1, body: 'foo'},
-      {id: 2, body: 'bar'}
+      { id: 1, body: 'foo' },
+      { id: 2, body: 'bar' }
     ]
 
     db.tags = [
-      {id: 1, body: 'Technology'},
-      {id: 2, body: 'Photography'},
-      {id: 3, body: 'photo'}
+      { id: 1, body: 'Technology' },
+      { id: 2, body: 'Photography' },
+      { id: 3, body: 'photo' }
     ]
 
     db.users = [
-      {id: 1, username: 'Jim'},
-      {id: 2, username: 'George'}
+      { id: 1, username: 'Jim', tel: '0123' },
+      { id: 2, username: 'George', tel: '123' }
     ]
 
     db.comments = [
-      {id: 1, body: 'foo', published: true, postId: 1, userId: 1},
-      {id: 2, body: 'bar', published: false, postId: 1, userId: 2},
-      {id: 3, body: 'baz', published: false, postId: 2, userId: 1},
-      {id: 4, body: 'qux', published: true, postId: 2, userId: 2},
-      {id: 5, body: 'quux', published: false, postId: 2, userId: 1}
+      { id: 1, body: 'foo', published: true, postId: 1, userId: 1 },
+      { id: 2, body: 'bar', published: false, postId: 1, userId: 2 },
+      { id: 3, body: 'baz', published: false, postId: 2, userId: 1 },
+      { id: 4, body: 'qux', published: true, postId: 2, userId: 2 },
+      { id: 5, body: 'quux', published: false, postId: 2, userId: 1 }
     ]
 
     db.refs = [
-      {id: 'abcd-1234', url: 'http://example.com/', postId: 1, userId: 1}
+      { id: 'abcd-1234', url: 'http://example.com/', postId: 1, userId: 1 }
+    ]
+
+    db.stringIds = [
+      { id: '1234' }
     ]
 
     db.deep = [
@@ -46,27 +49,27 @@ describe('Server', function () {
     ]
 
     db.nested = [
-      {resource: {name: 'dewey'}},
-      {resource: {name: 'cheatem'}},
-      {resource: {name: 'howe'}}
+      { resource: {name: 'dewey'} },
+      { resource: {name: 'cheatem'} },
+      { resource: {name: 'howe'} }
     ]
 
     db.list = [
-      {id: 1},
-      {id: 2},
-      {id: 3},
-      {id: 4},
-      {id: 5},
-      {id: 6},
-      {id: 7},
-      {id: 8},
-      {id: 9},
-      {id: 10},
-      {id: 11},
-      {id: 12},
-      {id: 13},
-      {id: 14},
-      {id: 15}
+      { id: 1 },
+      { id: 2 },
+      { id: 3 },
+      { id: 4 },
+      { id: 5 },
+      { id: 6 },
+      { id: 7 },
+      { id: 8 },
+      { id: 9 },
+      { id: 10 },
+      { id: 11 },
+      { id: 12 },
+      { id: 13 },
+      { id: 14 },
+      { id: 15 }
     ]
 
     server = jsonServer.create()
@@ -80,8 +83,8 @@ describe('Server', function () {
     server.use(router)
   })
 
-  describe('GET /db', function () {
-    it('should respond with json and full database', function (done) {
+  describe('GET /db', () => {
+    it('should respond with json and full database', (done) => {
       request(server)
         .get('/db')
         .expect('Content-Type', /json/)
@@ -90,8 +93,8 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource', function () {
-    it('should respond with json and corresponding resources', function (done) {
+  describe('GET /:resource', () => {
+    it('should respond with json and corresponding resources', (done) => {
       request(server)
         .get('/posts')
         .set('Origin', 'http://example.com/')
@@ -102,39 +105,47 @@ describe('Server', function () {
         .expect(200, done)
     })
 
-    it('should respond with 404 if resource is not found', function (done) {
+    it('should respond with 404 if resource is not found', (done) => {
       request(server)
         .get('/undefined')
         .expect(404, done)
     })
   })
 
-  describe('GET /:resource?attr=&attr=', function () {
-    it('should respond with json and filter resources', function (done) {
+  describe('GET /:resource?attr=&attr=', () => {
+    it('should respond with json and filter resources', (done) => {
       request(server)
         .get('/comments?postId=1&published=true')
         .expect('Content-Type', /json/)
-        .expect([db.comments[0]])
+        .expect([ db.comments[0] ])
         .expect(200, done)
     })
 
-    it('should support multiple filters', function (done) {
+    it('should be strict', (done) => {
+      request(server)
+        .get('/users?tel=123')
+        .expect('Content-Type', /json/)
+        .expect([ db.users[1] ])
+        .expect(200, done)
+    })
+
+    it('should support multiple filters', (done) => {
       request(server)
         .get('/comments?id=1&id=2')
         .expect('Content-Type', /json/)
-        .expect([db.comments[0], db.comments[1]])
+        .expect([ db.comments[0], db.comments[1] ])
         .expect(200, done)
     })
 
-    it('should support deep filter', function (done) {
+    it('should support deep filter', (done) => {
       request(server)
         .get('/deep?a.b=1')
         .expect('Content-Type', /json/)
-        .expect([db.deep[0]])
+        .expect([ db.deep[0] ])
         .expect(200, done)
     })
 
-    it('should ignore JSONP query parameters callback and _ ', function (done) {
+    it('should ignore JSONP query parameters callback and _ ', (done) => {
       request(server)
         .get('/comments?callback=1&_=1')
         .expect('Content-Type', /text/)
@@ -142,7 +153,7 @@ describe('Server', function () {
         .expect(200, done)
     })
 
-    it('should ignore unknown query parameters', function (done) {
+    it('should ignore unknown query parameters', (done) => {
       request(server)
         .get('/comments?foo=1&bar=2')
         .expect('Content-Type', /json/)
@@ -151,16 +162,16 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource?q=', function () {
-    it('should respond with json and make a full-text search', function (done) {
+  describe('GET /:resource?q=', () => {
+    it('should respond with json and make a full-text search', (done) => {
       request(server)
         .get('/tags?q=pho')
         .expect('Content-Type', /json/)
-        .expect([db.tags[1], db.tags[2]])
+        .expect([ db.tags[1], db.tags[2] ])
         .expect(200, done)
     })
 
-    it('should respond with json and make a deep full-text search', function (done) {
+    it('should respond with json and make a deep full-text search', (done) => {
       request(server)
         .get('/deep?q=1')
         .expect('Content-Type', /json/)
@@ -168,25 +179,25 @@ describe('Server', function () {
         .expect(200, done)
     })
 
-    it('should return an empty array when nothing is matched', function (done) {
+    it('should return an empty array when nothing is matched', (done) => {
       request(server)
         .get('/tags?q=nope')
         .expect('Content-Type', /json/)
-        .expect([])
+        .expect([ ])
         .expect(200, done)
     })
 
-    it('should support other query parameters', function (done) {
+    it('should support other query parameters', (done) => {
       request(server)
         .get('/comments?q=qu&published=true')
         .expect('Content-Type', /json/)
-        .expect([db.comments[3]])
+        .expect([ db.comments[3] ])
         .expect(200, done)
     })
   })
 
-  describe('GET /:resource?_end=', function () {
-    it('should respond with a sliced array', function (done) {
+  describe('GET /:resource?_end=', () => {
+    it('should respond with a sliced array', (done) => {
       request(server)
         .get('/comments?_end=2')
         .expect('Content-Type', /json/)
@@ -197,24 +208,24 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource?_sort=', function () {
-    it('should respond with json and sort on a field', function (done) {
+  describe('GET /:resource?_sort=', () => {
+    it('should respond with json and sort on a field', (done) => {
       request(server)
         .get('/tags?_sort=body')
         .expect('Content-Type', /json/)
-        .expect([db.tags[1], db.tags[0], db.tags[2]])
+        .expect([ db.tags[1], db.tags[0], db.tags[2] ])
         .expect(200, done)
     })
 
-    it('should reverse sorting with _order=DESC', function (done) {
+    it('should reverse sorting with _order=DESC', (done) => {
       request(server)
         .get('/tags?_sort=body&_order=DESC')
         .expect('Content-Type', /json/)
-        .expect([db.tags[2], db.tags[0], db.tags[1]])
+        .expect([ db.tags[2], db.tags[0], db.tags[1] ])
         .expect(200, done)
     })
 
-    it('should sort on numerical field', function (done) {
+    it('should sort on numerical field', (done) => {
       request(server)
         .get('/posts?_sort=id&_order=DESC')
         .expect('Content-Type', /json/)
@@ -222,41 +233,41 @@ describe('Server', function () {
         .expect(200, done)
     })
 
-    it('should sort on nested field', function (done) {
+    it('should sort on nested field', (done) => {
       request(server)
         .get('/nested?_sort=resource.name')
         .expect('Content-Type', /json/)
-        .expect([db.nested[1], db.nested[0], db.nested[2]])
+        .expect([ db.nested[1], db.nested[0], db.nested[2] ])
         .expect(200, done)
     })
   })
 
-  describe('GET /:resource?_start=&_end=', function () {
-    it('should respond with a sliced array', function (done) {
+  describe('GET /:resource?_start=&_end=', () => {
+    it('should respond with a sliced array', (done) => {
       request(server)
         .get('/comments?_start=1&_end=2')
         .expect('Content-Type', /json/)
-        .expect('x-total-count', db.comments.length.toString())
+        .expect('X-Total-Count', db.comments.length.toString())
         .expect('Access-Control-Expose-Headers', 'X-Total-Count')
         .expect(db.comments.slice(1, 2))
         .expect(200, done)
     })
   })
 
-  describe('GET /:resource?_start=&_limit=', function () {
-    it('should respond with a limited array', function (done) {
+  describe('GET /:resource?_start=&_limit=', () => {
+    it('should respond with a limited array', (done) => {
       request(server)
         .get('/comments?_start=1&_limit=1')
         .expect('Content-Type', /json/)
-        .expect('x-total-count', db.comments.length.toString())
+        .expect('X-Total-Count', db.comments.length.toString())
         .expect('Access-Control-Expose-Headers', 'X-Total-Count')
         .expect(db.comments.slice(1, 2))
         .expect(200, done)
     })
   })
 
-  describe('GET /:resource?_page=', function () {
-    it('should paginate', function (done) {
+  describe('GET /:resource?_page=', () => {
+    it('should paginate', (done) => {
       request(server)
         .get('/list?_page=2')
         .expect('Content-Type', /json/)
@@ -267,9 +278,9 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource?_page=&_limit=', function () {
-    it('should paginate with a custom limit', function (done) {
-      var link = [
+  describe('GET /:resource?_page=&_limit=', () => {
+    it('should paginate with a custom limit', (done) => {
+      const link = [
         '; rel="first"',
         '; rel="prev"',
         '; rel="next"',
@@ -287,8 +298,8 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource?attr_gte=&attr_lte=', function () {
-    it('should respond with a limited array', function (done) {
+  describe('GET /:resource?attr_gte=&attr_lte=', () => {
+    it('should respond with a limited array', (done) => {
       request(server)
         .get('/comments?id_gte=2&id_lte=3')
         .expect('Content-Type', /json/)
@@ -297,8 +308,8 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource?attr_ne=', function () {
-    it('should respond with a limited array', function (done) {
+  describe('GET /:resource?attr_ne=', () => {
+    it('should respond with a limited array', (done) => {
       request(server)
         .get('/comments?id_ne=1')
         .expect('Content-Type', /json/)
@@ -307,8 +318,8 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource?attr_like=', function () {
-    it('should respond with an array that matches the like operator (case insensitive)', function (done) {
+  describe('GET /:resource?attr_like=', () => {
+    it('should respond with an array that matches the like operator (case insensitive)', (done) => {
       request(server)
         .get('/tags?body_like=photo')
         .expect('Content-Type', /json/)
@@ -320,8 +331,8 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:parent/:parentId/:resource', function () {
-    it('should respond with json and corresponding nested resources', function (done) {
+  describe('GET /:parent/:parentId/:resource', () => {
+    it('should respond with json and corresponding nested resources', (done) => {
       request(server)
         .get('/posts/1/comments')
         .expect('Content-Type', /json/)
@@ -333,8 +344,8 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource/:id', function () {
-    it('should respond with json and corresponding resource', function (done) {
+  describe('GET /:resource/:id', () => {
+    it('should respond with json and corresponding resource', (done) => {
       request(server)
         .get('/posts/1')
         .expect('Content-Type', /json/)
@@ -342,7 +353,7 @@ describe('Server', function () {
         .expect(200, done)
     })
 
-    it('should support string id, respond with json and corresponding resource', function (done) {
+    it('should support string id, respond with json and corresponding resource', (done) => {
       request(server)
         .get('/refs/abcd-1234')
         .expect('Content-Type', /json/)
@@ -350,7 +361,15 @@ describe('Server', function () {
         .expect(200, done)
     })
 
-    it('should respond with 404 if resource is not found', function (done) {
+    it('should support integer id as string', (done) => {
+      request(server)
+        .get('/stringIds/1234')
+        .expect('Content-Type', /json/)
+        .expect(db.stringIds[0])
+        .expect(200, done)
+    })
+
+    it('should respond with 404 if resource is not found', (done) => {
       request(server)
         .get('/posts/9001')
         .expect('Content-Type', /json/)
@@ -359,11 +378,11 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource?_embed=', function () {
-    it('should respond with corresponding resources and embedded resources', function (done) {
-      var posts = _.cloneDeep(db.posts)
-      posts[0].comments = [db.comments[0], db.comments[1]]
-      posts[1].comments = [db.comments[2], db.comments[3], db.comments[4]]
+  describe('GET /:resource?_embed=', () => {
+    it('should respond with corresponding resources and embedded resources', (done) => {
+      const posts = _.cloneDeep(db.posts)
+      posts[0].comments = [ db.comments[0], db.comments[1] ]
+      posts[1].comments = [ db.comments[2], db.comments[3], db.comments[4] ]
       request(server)
         .get('/posts?_embed=comments')
         .expect('Content-Type', /json/)
@@ -372,12 +391,12 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource?_embed&_embed=', function () {
-    it('should respond with corresponding resources and embedded resources', function (done) {
-      var posts = _.cloneDeep(db.posts)
-      posts[0].comments = [db.comments[0], db.comments[1]]
-      posts[0].refs = [db.refs[0]]
-      posts[1].comments = [db.comments[2], db.comments[3], db.comments[4]]
+  describe('GET /:resource?_embed&_embed=', () => {
+    it('should respond with corresponding resources and embedded resources', (done) => {
+      const posts = _.cloneDeep(db.posts)
+      posts[0].comments = [ db.comments[0], db.comments[1] ]
+      posts[0].refs = [ db.refs[0] ]
+      posts[1].comments = [ db.comments[2], db.comments[3], db.comments[4] ]
       posts[1].refs = []
       request(server)
         .get('/posts?_embed=comments&_embed=refs')
@@ -387,34 +406,34 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource/:id?_embed=', function () {
-    it('should respond with corresponding resources and embedded resources', function (done) {
-      var posts = db.posts[0]
-      posts.comments = [db.comments[0], db.comments[1]]
+  describe('GET /:resource/:id?_embed=', () => {
+    it('should respond with corresponding resources and embedded resources', (done) => {
+      const post = _.cloneDeep(db.posts[0])
+      post.comments = [ db.comments[0], db.comments[1] ]
       request(server)
         .get('/posts/1?_embed=comments')
         .expect('Content-Type', /json/)
-        .expect(posts)
+        .expect(post)
         .expect(200, done)
     })
   })
 
-  describe('GET /:resource/:id?_embed=&_embed=', function () {
-    it('should respond with corresponding resource and embedded resources', function (done) {
-      var posts = db.posts[0]
-      posts.comments = [db.comments[0], db.comments[1]]
-      posts.refs = [db.refs[0]]
+  describe('GET /:resource/:id?_embed=&_embed=', () => {
+    it('should respond with corresponding resource and embedded resources', (done) => {
+      const post = _.cloneDeep(db.posts[0])
+      post.comments = [ db.comments[0], db.comments[1] ]
+      post.refs = [db.refs[0]]
       request(server)
         .get('/posts/1?_embed=comments&_embed=refs')
         .expect('Content-Type', /json/)
-        .expect(posts)
+        .expect(post)
         .expect(200, done)
     })
   })
 
-  describe('GET /:resource?_expand=', function () {
-    it('should respond with corresponding resource and expanded inner resources', function (done) {
-      var refs = _.cloneDeep(db.refs)
+  describe('GET /:resource?_expand=', () => {
+    it('should respond with corresponding resource and expanded inner resources', (done) => {
+      const refs = _.cloneDeep(db.refs)
       refs[0].post = db.posts[0]
       request(server)
         .get('/refs?_expand=post')
@@ -424,21 +443,21 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource/:id?_expand=', function () {
-    it('should respond with corresponding resource and expanded inner resources', function (done) {
-      var comments = db.comments[0]
-      comments.post = db.posts[0]
+  describe('GET /:resource/:id?_expand=', () => {
+    it('should respond with corresponding resource and expanded inner resources', (done) => {
+      const comment = _.cloneDeep(db.comments[0])
+      comment.post = db.posts[0]
       request(server)
         .get('/comments/1?_expand=post')
         .expect('Content-Type', /json/)
-        .expect(comments)
+        .expect(comment)
         .expect(200, done)
     })
   })
 
-  describe('GET /:resource?_expand=&_expand', function () {
-    it('should respond with corresponding resource and expanded inner resources', function (done) {
-      var refs = _.cloneDeep(db.refs)
+  describe('GET /:resource?_expand=&_expand', () => {
+    it('should respond with corresponding resource and expanded inner resources', (done) => {
+      const refs = _.cloneDeep(db.refs)
       refs[0].post = db.posts[0]
       refs[0].user = db.users[0]
       request(server)
@@ -449,9 +468,9 @@ describe('Server', function () {
     })
   })
 
-  describe('GET /:resource/:id?_expand=&_expand=', function () {
-    it('should respond with corresponding resource and expanded inner resources', function (done) {
-      var comments = db.comments[0]
+  describe('GET /:resource/:id?_expand=&_expand=', () => {
+    it('should respond with corresponding resource and expanded inner resources', (done) => {
+      const comments = db.comments[0]
       comments.post = db.posts[0]
       comments.user = db.users[0]
       request(server)
@@ -462,46 +481,49 @@ describe('Server', function () {
     })
   })
 
-  describe('POST /:resource', function () {
+  describe('POST /:resource', () => {
     it('should respond with json, create a resource and increment id',
-      function (done) {
+      (done) => {
         request(server)
           .post('/posts')
-          .send({body: 'foo', booleanValue: 'true', integerValue: '1'})
+          .send({body: 'foo', booleanValue: true, integerValue: 1})
           .expect('Content-Type', /json/)
           .expect({id: 3, body: 'foo', booleanValue: true, integerValue: 1})
           .expect(201)
-          .end(function (err, res) {
+          .end((err, res) => {
             if (err) return done(err)
             assert.equal(db.posts.length, 3)
             done()
           })
-      })
+      }
+    )
 
     it('should support x-www-form-urlencoded',
-      function (done) {
+      (done) => {
         request(server)
           .post('/posts')
           .type('form')
-          .send({body: 'foo'})
+          .send({body: 'foo', booleanValue: true, integerValue: 1})
           .expect('Content-Type', /json/)
-          .expect({id: 3, body: 'foo'})
+          // x-www-form-urlencoded will convert to string
+          .expect({id: 3, body: 'foo', booleanValue: 'true', integerValue: '1'})
           .expect(201)
-          .end(function (err, res) {
+          .end((err, res) => {
             if (err) return done(err)
             assert.equal(db.posts.length, 3)
             done()
           })
-      })
+      }
+    )
 
     it('should respond with json, create a resource and generate string id',
-      function (done) {
+      (done) => {
         request(server)
           .post('/refs')
           .send({url: 'http://foo.com/', postId: '1'})
           .expect('Content-Type', /json/)
           .expect(201)
-          .end(function (err, res) {
+          .end((err, res) => {
             if (err) return done(err)
             assert.equal(db.refs.length, 2)
             done()
@@ -509,8 +531,8 @@ describe('Server', function () {
       })
   })
 
-  describe('POST /:parent/:parentId/:resource', function () {
-    it('should respond with json and set parentId', function (done) {
+  describe('POST /:parent/:parentId/:resource', () => {
+    it('should respond with json and set parentId', (done) => {
       request(server)
         .post('/posts/1/comments')
         .send({body: 'foo'})
@@ -520,17 +542,17 @@ describe('Server', function () {
     })
   })
 
-  describe('PUT /:resource/:id', function () {
-    it('should respond with json and replace resource', function (done) {
+  describe('PUT /:resource/:id', () => {
+    it('should respond with json and replace resource', (done) => {
       var post = {id: 1, booleanValue: true, integerValue: 1}
       request(server)
         .put('/posts/1')
         // body property omitted to test that the resource is replaced
-        .send({id: 1, booleanValue: 'true', integerValue: '1'})
+        .send(post)
         .expect('Content-Type', /json/)
         .expect(post)
         .expect(200)
-        .end(function (err, res) {
+        .end((err, res) => {
           if (err) return done(err)
           // assert it was created in database too
           assert.deepEqual(db.posts[0], post)
@@ -538,25 +560,25 @@ describe('Server', function () {
         })
     })
 
-    it('should respond with 404 if resource is not found', function (done) {
+    it('should respond with 404 if resource is not found', (done) => {
       request(server)
         .put('/posts/9001')
-        .send({id: 1, body: 'bar', booleanValue: 'true', integerValue: '1'})
+        .send({id: 1, body: 'bar'})
         .expect('Content-Type', /json/)
         .expect({})
         .expect(404, done)
     })
   })
 
-  describe('PATCH /:resource/:id', function () {
-    it('should respond with json and update resource', function (done) {
+  describe('PATCH /:resource/:id', () => {
+    it('should respond with json and update resource', (done) => {
       request(server)
         .patch('/posts/1')
         .send({body: 'bar'})
         .expect('Content-Type', /json/)
         .expect({id: 1, body: 'bar'})
         .expect(200)
-        .end(function (err, res) {
+        .end((err, res) => {
           if (err) return done(err)
           // assert it was created in database too
           assert.deepEqual(db.posts[0], {id: 1, body: 'bar'})
@@ -564,7 +586,7 @@ describe('Server', function () {
         })
     })
 
-    it('should respond with 404 if resource is not found', function (done) {
+    it('should respond with 404 if resource is not found', (done) => {
       request(server)
         .patch('/posts/9001')
         .send({body: 'bar'})
@@ -574,13 +596,13 @@ describe('Server', function () {
     })
   })
 
-  describe('DELETE /:resource/:id', function () {
-    it('should respond with empty data, destroy resource and dependent resources', function (done) {
+  describe('DELETE /:resource/:id', () => {
+    it('should respond with empty data, destroy resource and dependent resources', (done) => {
       request(server)
         .del('/posts/1')
         .expect({})
         .expect(200)
-        .end(function (err, res) {
+        .end((err, res) => {
           if (err) return done(err)
           assert.equal(db.posts.length, 1)
           assert.equal(db.comments.length, 3)
@@ -588,7 +610,7 @@ describe('Server', function () {
         })
     })
 
-    it('should respond with 404 if resource is not found', function (done) {
+    it('should respond with 404 if resource is not found', (done) => {
       request(server)
         .del('/posts/9001')
         .expect('Content-Type', /json/)
@@ -597,9 +619,9 @@ describe('Server', function () {
     })
   })
 
-  describe('Static routes', function () {
-    describe('GET /', function () {
-      it('should respond with html', function (done) {
+  describe('Static routes', () => {
+    describe('GET /', () => {
+      it('should respond with html', (done) => {
         request(server)
           .get('/')
           .expect(/You're successfully running JSON Server/)
@@ -607,8 +629,8 @@ describe('Server', function () {
       })
     })
 
-    describe('GET /stylesheets/style.css', function () {
-      it('should respond with css', function (done) {
+    describe('GET /stylesheets/style.css', () => {
+      it('should respond with css', (done) => {
         request(server)
           .get('/stylesheets/style.css')
           .expect('Content-Type', /css/)
@@ -617,14 +639,14 @@ describe('Server', function () {
     })
   })
 
-  describe('Database state', function () {
-    it('should be accessible', function () {
+  describe('Database state', () => {
+    it('should be accessible', () => {
       assert(router.db.getState())
     })
   })
 
-  describe('Responses', function () {
-    it('should have no cache headers (for IE)', function (done) {
+  describe('Responses', () => {
+    it('should have no cache headers (for IE)', (done) => {
       request(server)
         .get('/db')
         .expect('Cache-Control', 'no-cache')
@@ -634,15 +656,15 @@ describe('Server', function () {
     })
   })
 
-  describe('Rewriter', function () {
-    it('should rewrite using prefix', function (done) {
+  describe('Rewriter', () => {
+    it('should rewrite using prefix', (done) => {
       request(server)
         .get('/api/posts/1')
         .expect(db.posts[0])
         .end(done)
     })
 
-    it('should rewrite using params', function (done) {
+    it('should rewrite using params', (done) => {
       request(server)
         .get('/blog/posts/1/show')
         .expect(db.posts[0])
@@ -657,16 +679,16 @@ describe('Server', function () {
     })
   })
 
-  describe('router.render', function (done) {
-    beforeEach(function () {
-      router.render = function (req, res) {
+  describe('router.render', (done) => {
+    beforeEach(() => {
+      router.render = (req, res) => {
         res.jsonp({
           data: res.locals.data
         })
       }
     })
 
-    it('should be possible to wrap response', function (done) {
+    it('should be possible to wrap response', (done) => {
       request(server)
         .get('/posts/1')
         .expect('Content-Type', /json/)
@@ -675,8 +697,8 @@ describe('Server', function () {
     })
   })
 
-  describe('router.db._.id', function (done) {
-    beforeEach(function () {
+  describe('router.db._.id', (done) => {
+    beforeEach(() => {
       router.db.setState({
         posts: [
           { _id: 1 }
@@ -686,7 +708,7 @@ describe('Server', function () {
       router.db._.id = '_id'
     })
 
-    it('should be possible to GET using a different id property', function (done) {
+    it('should be possible to GET using a different id property', (done) => {
       request(server)
         .get('/posts/1')
         .expect('Content-Type', /json/)
@@ -694,12 +716,12 @@ describe('Server', function () {
         .expect(200, done)
     })
 
-    it('should be possible to POST using a different id property', function (done) {
+    it('should be possible to POST using a different id property', (done) => {
       request(server)
         .post('/posts')
         .send({ body: 'hello' })
         .expect('Content-Type', /json/)
-        .expect({_id: 2, body: 'hello'})
+        .expect({ _id: 2, body: 'hello' })
         .expect(201, done)
     })
   })
diff --git a/test/server/singular.js b/test/server/singular.js
index 617bc3749..509a4785e 100644
--- a/test/server/singular.js
+++ b/test/server/singular.js
@@ -1,11 +1,10 @@
-var request = require('supertest')
-var jsonServer = require('../../src/server')
+const request = require('supertest')
+const jsonServer = require('../../src/server')
 
-/* global beforeEach, describe, it */
 describe('Server', function () {
-  var server
-  var router
-  var db
+  let server
+  let router
+  let db
 
   beforeEach(function () {
     db = {}
@@ -32,7 +31,7 @@ describe('Server', function () {
 
   describe('POST /:resource', function () {
     it('should create resource', function (done) {
-      var user = { name: 'bar' }
+      const user = { name: 'bar' }
       request(server)
         .post('/user')
         .send(user)
@@ -43,7 +42,7 @@ describe('Server', function () {
 
   describe('PUT /:resource', function () {
     it('should update resource', function (done) {
-      var user = { name: 'bar' }
+      const user = { name: 'bar' }
       request(server)
         .put('/user')
         .send(user)
diff --git a/test/server/utils.js b/test/server/utils.js
index 4036f58aa..a611db22e 100644
--- a/test/server/utils.js
+++ b/test/server/utils.js
@@ -1,30 +1,10 @@
-var assert = require('assert')
-var utils = require('../../src/server/utils')
-
-/* global describe, it */
+const assert = require('assert')
+const utils = require('../../src/server/utils')
 
 describe('utils', function () {
-  describe('toNative', function () {
-    it('should convert string to native type', function () {
-      // should convert
-      assert.strictEqual(utils.toNative('1'), 1)
-      assert.strictEqual(utils.toNative('0'), 0)
-      assert.strictEqual(utils.toNative('true'), true)
-      // should not convert
-      assert.strictEqual(utils.toNative(''), '')
-      assert.strictEqual(utils.toNative('\t\n'), '\t\n')
-      assert.strictEqual(utils.toNative('1 '), '1 ')
-      assert.strictEqual(utils.toNative('01'), '01')
-      assert.strictEqual(utils.toNative(' 1'), ' 1')
-      assert.strictEqual(utils.toNative('string'), 'string')
-      assert.strictEqual(utils.toNative(1), 1)
-      assert.strictEqual(utils.toNative(true), true)
-    })
-  })
-
   describe('getPage', function () {
-    var array = [1, 2, 3, 4, 5]
-    var perPage = 2
+    const array = [1, 2, 3, 4, 5]
+    const perPage = 2
 
     it('should return first page', function () {
       assert.deepEqual(
diff --git a/test/server/validate-data.js b/test/server/validate-data.js
new file mode 100644
index 000000000..808721576
--- /dev/null
+++ b/test/server/validate-data.js
@@ -0,0 +1,24 @@
+const assert = require('assert')
+const validateData = require('../../src/server/router/validate-data')
+
+describe('validateData', () => {
+  it('should throw an error if data contains /', () => {
+    assert.throws(
+      () => validateData({ 'a/b': [] }),
+      /found \//
+    )
+  })
+
+  it('should throw an error if data is an array', () => {
+    assert.throws(
+      () => validateData([]),
+      /must be an object/
+    )
+  })
+
+  it('shouldn\'t throw an error', () => {
+    assert.doesNotThrow(
+      () => validateData({ a: [] })
+    )
+  })
+})
From 526ff59aff86d4477cbaed90e8bd248c0f793e37 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sat, 12 Nov 2016 02:01:26 +0100
Subject: [PATCH 028/494] 0.9.0
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 9bab48524..42fe72337 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.9.0-beta.2",
+  "version": "0.9.0",
   "description": "Serves JSON files through REST routes.",
   "main": "./lib/server/index.js",
   "bin": "./bin/index.js",
From d46cbd20f008a2b98ed775a605cee8a6e46559e3 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sat, 12 Nov 2016 02:22:30 +0100
Subject: [PATCH 029/494] Add prepublish
---
 package.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 42fe72337..29deed0bb 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,8 @@
     "test:server": "cross-env NODE_ENV=test mocha test/server/*.js",
     "start": "node bin",
     "prepush": "npm t",
-    "build": "babel src -d lib --copy-files"
+    "build": "babel src -d lib --copy-files",
+    "prepublish": "npm run build"
   },
   "repository": {
     "type": "git",
From 1cb4e3e27ebd87ad94f7a8cabe13bab72c4dad85 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sat, 12 Nov 2016 02:24:44 +0100
Subject: [PATCH 030/494] Update README.md
---
 README.md | 10 ----------
 1 file changed, 10 deletions(-)
diff --git a/README.md b/README.md
index 37c7db91a..e5df52995 100644
--- a/README.md
+++ b/README.md
@@ -51,16 +51,6 @@ Also when doing requests, its good to know that
 $ npm install -g json-server
 ```
 
-### Beta
-
-To try [v0.9.0-beta](https://github.com/typicode/json-server/tree/next)
-
-```bash
-$ npm install -g json-server@next
-```
-
-
-
 ## Routes
 
 Based on the previous `db.json` file, here are all the default routes. You can also add [other routes](#add-routes) using `--routes`.
From a42373eaf29e91f11217d16beb41a19452f54f73 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sat, 12 Nov 2016 02:42:06 +0100
Subject: [PATCH 031/494] Add markdown-toc
---
 package.json | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/package.json b/package.json
index 29deed0bb..7ebe09036 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
     "babel-register": "^6.16.3",
     "cross-env": "^2.0.1",
     "husky": "^0.11.4",
+    "markdown-toc": "^0.13.0",
     "mkdirp": "^0.5.1",
     "mocha": "^3.1.2",
     "os-tmpdir": "^1.0.1",
@@ -50,6 +51,7 @@
     "start": "node bin",
     "prepush": "npm t",
     "build": "babel src -d lib --copy-files",
+    "toc": "markdown-toc -i README.md",
     "prepublish": "npm run build"
   },
   "repository": {
From 4be7538412a7648509084fd83e8a862f1b104586 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sat, 12 Nov 2016 02:42:29 +0100
Subject: [PATCH 032/494] Update README.md
---
 README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index e5df52995..f78223220 100644
--- a/README.md
+++ b/README.md
@@ -8,9 +8,57 @@ Created with <3 for front-end developers who need a quick back-end for prototypi
 * [JSONPlaceholder - Live running version](http://jsonplaceholder.typicode.com)
 
 See also:
-* :hotel: [hotel - Get local domains in seconds](https://github.com/typicode/hotel)
+* :hotel: [hotel - Start apps from your browser and get local dev domains in seconds](https://github.com/typicode/hotel)
 * :dog: [husky - Git hooks made easy](https://github.com/typicode/husky)
 
+## Table of contents
+
+
+
+
+
+- [Example](#example)
+- [Install](#install)
+- [Routes](#routes)
+  * [Plural routes](#plural-routes)
+  * [Singular routes](#singular-routes)
+  * [Filter](#filter)
+  * [Paginate](#paginate)
+  * [Sort](#sort)
+  * [Slice](#slice)
+  * [Operators](#operators)
+  * [Full-text search](#full-text-search)
+  * [Relationships](#relationships)
+  * [Database](#database)
+  * [Homepage](#homepage)
+- [Extras](#extras)
+  * [Static file server](#static-file-server)
+  * [Alternative port](#alternative-port)
+  * [Access from anywhere](#access-from-anywhere)
+  * [Remote schema](#remote-schema)
+  * [Generate random data](#generate-random-data)
+  * [HTTPS](#https)
+  * [Add custom routes](#add-custom-routes)
+  * [Add middlewares](#add-middlewares)
+  * [CLI usage](#cli-usage)
+  * [Module](#module)
+    + [Simple example](#simple-example)
+    + [Custom routes example](#custom-routes-example)
+    + [Access control example](#access-control-example)
+    + [Custom output example](#custom-output-example)
+    + [Rewriter example](#rewriter-example)
+    + [Mounting JSON Server on another endpoint example](#mounting-json-server-on-another-endpoint-example)
+  * [Deployment](#deployment)
+- [Links](#links)
+  * [Video](#video)
+  * [Articles](#articles)
+  * [Third-party tools](#third-party-tools)
+- [License](#license)
+
+
+
+ 
+
 ## Example
 
 Create a `db.json` file
@@ -39,7 +87,8 @@ Now if you go to [http://localhost:3000/posts/1](), you'll get
 { "id": 1, "title": "json-server", "author": "typicode" }
 ```
 
-Also when doing requests, its good to know that
+Also when doing requests, it's good to know that:
+
 - If you make POST, PUT, PATCH or DELETE requests, changes will be automatically and safely saved to `db.json` using [lowdb](https://github.com/typicode/lowdb).
 - Your request body JSON should be object enclosed, just like the GET output. (for example `{"name": "Foobar"}`)
 - Id values are not mutable. Any `id` value in the body of your PUT or PATCH request wil be ignored. Only a value set in a POST request wil be respected, but only if not already taken.
From b5eec153f7ca9551338e3b884c0d140f93cde42e Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 17 Nov 2016 13:22:53 +0100
Subject: [PATCH 033/494] Update package.json
---
 package.json | 3 +++
 1 file changed, 3 insertions(+)
diff --git a/package.json b/package.json
index 7ebe09036..2fdee8d1d 100644
--- a/package.json
+++ b/package.json
@@ -85,5 +85,8 @@
     "env": {
       "mocha": true
     }
+  },
+  "engines": {
+    "node": ">= 0.12"
   }
 }
From eca6b763f2b904e6c0739f14cd4f9eb04a7c2a27 Mon Sep 17 00:00:00 2001
From: Jan Trienes 
Date: Mon, 21 Nov 2016 02:24:35 +0100
Subject: [PATCH 034/494] fix filter for boolean value false (#412) (#413)
---
 src/server/router/plural.js | 2 +-
 test/server/plural.js       | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/server/router/plural.js b/src/server/router/plural.js
index 24ecf850c..b949465b0 100644
--- a/src/server/router/plural.js
+++ b/src/server/router/plural.js
@@ -120,7 +120,7 @@ module.exports = (db, name) => {
               const path = key.replace(/(_lte|_gte|_ne|_like)$/, '')
               const elementValue = _.get(element, path)
 
-              if (!elementValue) {
+              if (elementValue == null) {
                 return
               }
 
diff --git a/test/server/plural.js b/test/server/plural.js
index 1cd47748c..fa0b751b9 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -194,6 +194,14 @@ describe('Server', () => {
         .expect([ db.comments[3] ])
         .expect(200, done)
     })
+
+    it('should support filtering by boolean value false', (done) => {
+      request(server)
+        .get('/comments?published=false')
+        .expect('Content-Type', /json/)
+        .expect([ db.comments[1], db.comments[2], db.comments[4] ])
+        .expect(200, done)
+    })
   })
 
   describe('GET /:resource?_end=', () => {
From b5e4fcc9d2fe4167642fb4cf1f99532392374d5c Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 21 Nov 2016 02:39:04 +0100
Subject: [PATCH 035/494] Update underscore-db dependency
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 2fdee8d1d..c807ef608 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
     "request": "^2.72.0",
     "server-destroy": "^1.0.1",
     "shortid": "^2.2.6",
-    "underscore-db": "^0.12.0",
+    "underscore-db": "^0.12.1",
     "update-notifier": "^1.0.2",
     "yargs": "^6.0.0"
   },
From f54de70738d7f8a95892f7ba285facc3dd98a01a Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 21 Nov 2016 02:39:29 +0100
Subject: [PATCH 036/494] Update test
---
 src/server/router/plural.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/server/router/plural.js b/src/server/router/plural.js
index b949465b0..0c8b1173b 100644
--- a/src/server/router/plural.js
+++ b/src/server/router/plural.js
@@ -120,7 +120,7 @@ module.exports = (db, name) => {
               const path = key.replace(/(_lte|_gte|_ne|_like)$/, '')
               const elementValue = _.get(element, path)
 
-              if (elementValue == null) {
+              if (elementValue === undefined) {
                 return
               }
 
From 6051dde5f41cf58eb30e7154ea14cfafba23ee6a Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 21 Nov 2016 02:43:18 +0100
Subject: [PATCH 037/494] Update CHANGELOG.md
---
 CHANGELOG.md | 5 +++++
 1 file changed, 5 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1b4cbfdd8..8e1505d97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Change Log
 
+## [0.9.1][2016-11-21]
+
+* Fix
+ * [#412](https://github.com/typicode/json-server/issues/412)
+
 ## [0.9.0][2016-11-11]
 
 * Shorter `uuid`
From 05e147427df6d7c1f64ca17cf1247acb787dc44d Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 21 Nov 2016 02:43:35 +0100
Subject: [PATCH 038/494] 0.9.1
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index c807ef608..5781fd0bd 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.9.0",
+  "version": "0.9.1",
   "description": "Serves JSON files through REST routes.",
   "main": "./lib/server/index.js",
   "bin": "./bin/index.js",
From 16577f1bfd937b95e29bb542cb51cae82c79757e Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 21 Nov 2016 14:57:01 +0100
Subject: [PATCH 039/494] Update CHANGELOG.md
---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e1505d97..dea8a3c1b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
 
 * Fix
  * [#412](https://github.com/typicode/json-server/issues/412)
+ * [#451]https://github.com/typicode/json-server/issues/411
 
 ## [0.9.0][2016-11-11]
 
From d3883f91430461827d4e5698d498770c1fb0120b Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 21 Nov 2016 14:57:11 +0100
Subject: [PATCH 040/494] Update CHANGELOG.md
---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dea8a3c1b..8b90412d7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,7 @@
 
 * Fix
  * [#412](https://github.com/typicode/json-server/issues/412)
- * [#451]https://github.com/typicode/json-server/issues/411
+ * [#451](https://github.com/typicode/json-server/issues/411)
 
 ## [0.9.0][2016-11-11]
 
From 6e75107638896430969dd3031bec4c0d823f9a0e Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 22 Nov 2016 12:59:17 +0100
Subject: [PATCH 041/494] Update README.md
---
 README.md | 1 +
 1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index f78223220..4a9b8a73e 100644
--- a/README.md
+++ b/README.md
@@ -522,6 +522,7 @@ You can deploy JSON Server. For example, [JSONPlaceholder](http://jsonplaceholde
 * [ng-admin: Add an AngularJS admin GUI to any RESTful API](http://marmelab.com/blog/2014/09/15/easy-backend-for-your-restful-api.html)
 * [Fast prototyping using Restangular and Json-server](http://glebbahmutov.com/blog/fast-prototyping-using-restangular-and-json-server/)
 * [Create a Mock REST API in Seconds for Prototyping your Frontend](https://coligo.io/create-mock-rest-api-with-json-server/)
+* [No API? No Problem! Rapid Development via Mock APIs](https://medium.com/@housecor/rapid-development-via-mock-apis-e559087be066#.93d7w8oro)
 
 ### Third-party tools
 
From edbb8603007ac57ed98155758844002b6b344e9e Mon Sep 17 00:00:00 2001
From: Sam Blowes 
Date: Fri, 25 Nov 2016 14:56:20 +0000
Subject: [PATCH 042/494] Fix invalid HTML, Improve formatting (#422)
---
 src/server/public/index.html | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/src/server/public/index.html b/src/server/public/index.html
index ecd16b493..bdac2a7ad 100644
--- a/src/server/public/index.html
+++ b/src/server/public/index.html
@@ -26,19 +26,17 @@ Routes
       
         Here are the resources that JSON Server has loaded:
       
-      
-        
-      
-
+      
+      
       
         You can view database current state at any time:
-        
       
-
+      
+      
       
         You can use any HTTP verbs (GET, POST, PUT, PATCH and DELETE) and access your resources from anywhere
         using CORS and JSONP.
From 3f355b3adabc3f62d4400e0f09906ce8fb32a267 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sun, 27 Nov 2016 20:12:38 +0100
Subject: [PATCH 043/494] Check if file is not null when watching dir
---
 src/cli/run.js | 38 ++++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 16 deletions(-)
diff --git a/src/cli/run.js b/src/cli/run.js
index 648974c2d..1dc7fd1a4 100644
--- a/src/cli/run.js
+++ b/src/cli/run.js
@@ -185,21 +185,25 @@ module.exports = function (argv) {
       // Since lowdb uses atomic writing, directory is watched instead of file
       const watchedDir = path.dirname(source)
       fs.watch(watchedDir, (event, file) => {
-        const watchedFile = path.resolve(watchedDir, file)
-        if (watchedFile === path.resolve(source)) {
-          if (is.JSON(watchedFile)) {
-            var obj = JSON.parse(fs.readFileSync(watchedFile))
-            // Compare .json file content with in memory database
-            var isDatabaseDifferent = !_.isEqual(obj, app.db.getState())
-            if (isDatabaseDifferent) {
+        // https://github.com/typicode/json-server/issues/420
+        // file can be null
+        if (file) {
+          const watchedFile = path.resolve(watchedDir, file)
+          if (watchedFile === path.resolve(source)) {
+            if (is.JSON(watchedFile)) {
+              var obj = JSON.parse(fs.readFileSync(watchedFile))
+              // Compare .json file content with in memory database
+              var isDatabaseDifferent = !_.isEqual(obj, app.db.getState())
+              if (isDatabaseDifferent) {
+                console.log(chalk.gray(`  ${source} has changed, reloading...`))
+                server && server.destroy()
+                start()
+              }
+            } else {
               console.log(chalk.gray(`  ${source} has changed, reloading...`))
               server && server.destroy()
               start()
             }
-          } else {
-            console.log(chalk.gray(`  ${source} has changed, reloading...`))
-            server && server.destroy()
-            start()
           }
         }
       })
@@ -208,11 +212,13 @@ module.exports = function (argv) {
       if (argv.routes) {
         const watchedDir = path.dirname(argv.routes)
         fs.watch(watchedDir, (event, file) => {
-          const watchedFile = path.resolve(watchedDir, file)
-          if (watchedFile === path.resolve(argv.routes)) {
-            console.log(chalk.gray(`  ${argv.routes} has changed, reloading...`))
-            server && server.destroy()
-            start()
+          if (file) {
+            const watchedFile = path.resolve(watchedDir, file)
+            if (watchedFile === path.resolve(argv.routes)) {
+              console.log(chalk.gray(`  ${argv.routes} has changed, reloading...`))
+              server && server.destroy()
+              start()
+            }
           }
         })
       }
From fdab5ee4d0cd4a21693b86631aeb3f93344f2999 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 28 Nov 2016 08:55:14 +0100
Subject: [PATCH 044/494] Create appveyor.yml
---
 appveyor.yml | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 appveyor.yml
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 000000000..5fef32bbf
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,21 @@
+# Test against this version of Node.js
+environment:
+  nodejs_version: "7"
+
+# Install scripts. (runs after repo cloning)
+install:
+  # Get the latest stable version of Node.js
+  - ps: Install-Product node $env:nodejs_version
+  # install modules
+  - npm install
+
+# Post-install test scripts.
+test_script:
+  # Output useful info for debugging.
+  - node --version
+  - npm --version
+  # run tests
+  - npm test
+
+# Don't actually build.
+build: off
From 2ce7cd37b289e6e286667262f223939ecf46c954 Mon Sep 17 00:00:00 2001
From: Sam Blowes 
Date: Mon, 28 Nov 2016 11:09:58 +0000
Subject: [PATCH 045/494] Fix broken links (#426)
---
 README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 4a9b8a73e..945a9aaf4 100644
--- a/README.md
+++ b/README.md
@@ -102,7 +102,7 @@ $ npm install -g json-server
 
 ## Routes
 
-Based on the previous `db.json` file, here are all the default routes. You can also add [other routes](#add-routes) using `--routes`.
+Based on the previous `db.json` file, here are all the default routes. You can also add [other routes](#add-custom-routes) using `--routes`.
 
 ### Plural routes
 
@@ -211,7 +211,7 @@ GET /comments?_expand=post
 GET /comments/1?_expand=post
 ```
 
-To get or create nested resources (by default one level, [add routes](#add-routes) for more)
+To get or create nested resources (by default one level, [add custom routes](#add-custom-routes) for more)
 
 ```
 GET  /posts/1/comments
From c527e1ef87ec79818c7c1376e8451676782e4f6e Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 28 Nov 2016 13:30:43 +0100
Subject: [PATCH 046/494] Fix nohup issue
---
 CHANGELOG.md   | 5 +++++
 src/cli/run.js | 6 +++++-
 2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8b90412d7..4179153a3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Change Log
 
+## [Unreleased][Unreleased]
+
+* Fix [#221](https://github.com/typicode/json-server/issues/221) nohup support
+* Fix [#420](https://github.com/typicode/json-server/issues/420) TypeError when watching db.json
+
 ## [0.9.1][2016-11-21]
 
 * Fix
diff --git a/src/cli/run.js b/src/cli/run.js
index 1dc7fd1a4..49a5fd3e9 100644
--- a/src/cli/run.js
+++ b/src/cli/run.js
@@ -160,7 +160,11 @@ module.exports = function (argv) {
       chalk.gray('  Type s + enter at any time to create a snapshot of the database')
     )
 
-    process.stdin.resume()
+    // Support nohup
+    // https://github.com/typicode/json-server/issues/221
+    process.stdin.on('error', (err) => {
+      console.log('  Error, can\'t read from stdin')
+    })
     process.stdin.setEncoding('utf8')
     process.stdin.on('data', (chunk) => {
       if (chunk.trim().toLowerCase() === 's') {
From b6b48faceea09a145da3e3d0b64567bce6f5b33a Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 28 Nov 2016 13:33:29 +0100
Subject: [PATCH 047/494] Fix standard error
---
 src/cli/run.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cli/run.js b/src/cli/run.js
index 49a5fd3e9..92fcbd5c9 100644
--- a/src/cli/run.js
+++ b/src/cli/run.js
@@ -162,7 +162,7 @@ module.exports = function (argv) {
 
     // Support nohup
     // https://github.com/typicode/json-server/issues/221
-    process.stdin.on('error', (err) => {
+    process.stdin.on('error', () => {
       console.log('  Error, can\'t read from stdin')
     })
     process.stdin.setEncoding('utf8')
From cb1d474ac63690bd3db9fd76b142a4fe9d9d1b62 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Mon, 28 Nov 2016 14:07:30 +0100
Subject: [PATCH 048/494] Update run.js
---
 src/cli/run.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/cli/run.js b/src/cli/run.js
index 92fcbd5c9..9c739097b 100644
--- a/src/cli/run.js
+++ b/src/cli/run.js
@@ -163,7 +163,8 @@ module.exports = function (argv) {
     // Support nohup
     // https://github.com/typicode/json-server/issues/221
     process.stdin.on('error', () => {
-      console.log('  Error, can\'t read from stdin')
+      console.log(`  Error, can't read from stdin`)
+      console.log(`  Creating a snapshot from the CLI won't be possible`)
     })
     process.stdin.setEncoding('utf8')
     process.stdin.on('data', (chunk) => {
From 814bae7969b226f9cd69fecc59d99b8012323893 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 29 Nov 2016 08:54:28 +0100
Subject: [PATCH 049/494] 0.9.2
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 5781fd0bd..8886f1ceb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.9.1",
+  "version": "0.9.2",
   "description": "Serves JSON files through REST routes.",
   "main": "./lib/server/index.js",
   "bin": "./bin/index.js",
From 060d194b044835bf7eb5adfec0eca72ee9b193fe Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 29 Nov 2016 07:56:14 +0100
Subject: [PATCH 050/494] Update CHANGELOG.md
---
 CHANGELOG.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4179153a3..8e9fdbb9b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,9 @@
 # Change Log
 
-## [Unreleased][Unreleased]
+## [0.9.2][2016-11-29]
 
-* Fix [#221](https://github.com/typicode/json-server/issues/221) nohup support
-* Fix [#420](https://github.com/typicode/json-server/issues/420) TypeError when watching db.json
+* Fix [#221](https://github.com/typicode/json-server/issues/221) `nohup` support
+* Fix [#420](https://github.com/typicode/json-server/issues/420) TypeError when watching `db.json`
 
 ## [0.9.1][2016-11-21]
 
From 485378d22203778f839e4f3ff66072d4d6f157b6 Mon Sep 17 00:00:00 2001
From: zhangbiaoguang 
Date: Tue, 29 Nov 2016 18:55:30 +0800
Subject: [PATCH 051/494] fixed the bug on windows: SyntaxError-Unexpected end
 of input
---
 src/cli/run.js | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/cli/run.js b/src/cli/run.js
index 648974c2d..ebdbd2c05 100644
--- a/src/cli/run.js
+++ b/src/cli/run.js
@@ -188,7 +188,14 @@ module.exports = function (argv) {
         const watchedFile = path.resolve(watchedDir, file)
         if (watchedFile === path.resolve(source)) {
           if (is.JSON(watchedFile)) {
-            var obj = JSON.parse(fs.readFileSync(watchedFile))
+            var obj = null;
+            try {
+                obj = JSON.parse(fs.readFileSync(watchedFile));
+            } catch (e) {
+                console.log('The format of the json file is not right, please check.');
+                console.dir(e);
+                return;
+            }
             // Compare .json file content with in memory database
             var isDatabaseDifferent = !_.isEqual(obj, app.db.getState())
             if (isDatabaseDifferent) {
From f2f96514e5984962237103f0adc8f4d2e084922f Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 6 Dec 2016 13:05:28 +0100
Subject: [PATCH 052/494] Update README.md
---
 README.md | 1 +
 1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 945a9aaf4..1916c1aa2 100644
--- a/README.md
+++ b/README.md
@@ -530,6 +530,7 @@ You can deploy JSON Server. For example, [JSONPlaceholder](http://jsonplaceholde
 * [Docker JSON Server](https://github.com/clue/docker-json-server)
 * [JSON Server GUI](https://github.com/naholyr/json-server-gui)
 * [JSON file generator](https://github.com/dfsq/json-server-init)
+* [JSON Server extension](https://github.com/maty21/json-server-extension)
 
 ## License
 
From 46a5259584fde5860f8c58b9c125947617cded76 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 6 Dec 2016 23:43:26 +0100
Subject: [PATCH 053/494] Add stricter tests
---
 src/server/router/plural.js |  1 +
 test/server/plural.js       | 11 ++++++++---
 2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/server/router/plural.js b/src/server/router/plural.js
index 0c8b1173b..42a5e03be 100644
--- a/src/server/router/plural.js
+++ b/src/server/router/plural.js
@@ -253,6 +253,7 @@ module.exports = (db, name) => {
   function update (req, res, next) {
     const id = req.params.id
     let chain = db.get(name)
+    console.log(req.body)
 
     chain = req.method === 'PATCH'
       ? chain.updateById(id, req.body)
diff --git a/test/server/plural.js b/test/server/plural.js
index fa0b751b9..d9993303d 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -551,10 +551,11 @@ describe('Server', () => {
   })
 
   describe('PUT /:resource/:id', () => {
-    it('should respond with json and replace resource', (done) => {
+    it.only('should respond with json and replace resource', (done) => {
       var post = {id: 1, booleanValue: true, integerValue: 1}
       request(server)
         .put('/posts/1')
+        .set('Accept', 'application/json')
         // body property omitted to test that the resource is replaced
         .send(post)
         .expect('Content-Type', /json/)
@@ -562,8 +563,11 @@ describe('Server', () => {
         .expect(200)
         .end((err, res) => {
           if (err) return done(err)
+          // TODO find a "supertest" way to test this
+          // https://github.com/typicode/json-server/issues/396
+          assert.deepStrictEqual(res.body, post)
           // assert it was created in database too
-          assert.deepEqual(db.posts[0], post)
+          assert.deepStrictEqual(db.posts[0], post)
           done()
         })
     })
@@ -588,8 +592,9 @@ describe('Server', () => {
         .expect(200)
         .end((err, res) => {
           if (err) return done(err)
+          assert.deepStrictEqual(res.body, post)
           // assert it was created in database too
-          assert.deepEqual(db.posts[0], {id: 1, body: 'bar'})
+          assert.deepStrictEqual(db.posts[0], {id: 1, body: 'bar'})
           done()
         })
     })
From 3df272dbe331a0ea5703b724717b1c9df1955af1 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 6 Dec 2016 23:49:21 +0100
Subject: [PATCH 054/494] Update package.json
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 8886f1ceb..be3d73a6e 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
     "request": "^2.72.0",
     "server-destroy": "^1.0.1",
     "shortid": "^2.2.6",
-    "underscore-db": "^0.12.1",
+    "underscore-db": "^0.12.2",
     "update-notifier": "^1.0.2",
     "yargs": "^6.0.0"
   },
From d0596e1386214d4211a30700e951e209ead852b2 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 6 Dec 2016 23:51:01 +0100
Subject: [PATCH 055/494] clean
---
 src/server/router/plural.js | 1 -
 test/server/plural.js       | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/server/router/plural.js b/src/server/router/plural.js
index 42a5e03be..0c8b1173b 100644
--- a/src/server/router/plural.js
+++ b/src/server/router/plural.js
@@ -253,7 +253,6 @@ module.exports = (db, name) => {
   function update (req, res, next) {
     const id = req.params.id
     let chain = db.get(name)
-    console.log(req.body)
 
     chain = req.method === 'PATCH'
       ? chain.updateById(id, req.body)
diff --git a/test/server/plural.js b/test/server/plural.js
index d9993303d..6408796e1 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -551,7 +551,7 @@ describe('Server', () => {
   })
 
   describe('PUT /:resource/:id', () => {
-    it.only('should respond with json and replace resource', (done) => {
+    it('should respond with json and replace resource', (done) => {
       var post = {id: 1, booleanValue: true, integerValue: 1}
       request(server)
         .put('/posts/1')
From 24b2c9f1b6c8db28950a619000d84faf9c4b2df8 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Tue, 6 Dec 2016 23:52:26 +0100
Subject: [PATCH 056/494] Update CHANGELOG.md
---
 CHANGELOG.md | 4 ++++
 1 file changed, 4 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e9fdbb9b..2ac401867 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Change Log
 
+## [0.9.3][unreleased]
+
+* Fix [#396](https://github.com/typicode/json-server/issues/396)
+
 ## [0.9.2][2016-11-29]
 
 * Fix [#221](https://github.com/typicode/json-server/issues/221) `nohup` support
From d6528665a13b9a8e925337b3ea2c8159e0cbb693 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Wed, 7 Dec 2016 09:28:33 +0100
Subject: [PATCH 057/494] Update CHANGELOG.md
---
 CHANGELOG.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2ac401867..89ce05272 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,8 @@
 # Change Log
 
-## [0.9.3][unreleased]
+## [0.9.3][2016-12-07]
 
-* Fix [#396](https://github.com/typicode/json-server/issues/396)
+* Fix [#396](https://github.com/typicode/json-server/issues/396) PUT/PATCH saves the updated item with an id that has been converted to string
 
 ## [0.9.2][2016-11-29]
 
From 84493e07db7d5b9a165c3075fdd4a61127fc9f20 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Wed, 7 Dec 2016 09:28:52 +0100
Subject: [PATCH 058/494] 0.9.3
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index be3d73a6e..c6216dfc4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.9.2",
+  "version": "0.9.3",
   "description": "Serves JSON files through REST routes.",
   "main": "./lib/server/index.js",
   "bin": "./bin/index.js",
From b2bcabb71e273a2b655d71a89a9a4b5378b73450 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Wed, 7 Dec 2016 09:39:44 +0100
Subject: [PATCH 059/494] Fix PATCH test
---
 test/server/plural.js | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/test/server/plural.js b/test/server/plural.js
index 6408796e1..9a0918b04 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -584,17 +584,19 @@ describe('Server', () => {
 
   describe('PATCH /:resource/:id', () => {
     it('should respond with json and update resource', (done) => {
+      var partial = {body: 'bar'}
+      var post = {id: 1, body: 'bar'}
       request(server)
         .patch('/posts/1')
-        .send({body: 'bar'})
+        .send(partial)
         .expect('Content-Type', /json/)
-        .expect({id: 1, body: 'bar'})
+        .expect(post)
         .expect(200)
         .end((err, res) => {
           if (err) return done(err)
           assert.deepStrictEqual(res.body, post)
           // assert it was created in database too
-          assert.deepStrictEqual(db.posts[0], {id: 1, body: 'bar'})
+          assert.deepStrictEqual(db.posts[0], post)
           done()
         })
     })
From 427e6add1fc0bcc8d9f27dd00ba28e587d9cd89a Mon Sep 17 00:00:00 2001
From: typicode 
Date: Wed, 7 Dec 2016 09:41:42 +0100
Subject: [PATCH 060/494] 0.9.4
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index c6216dfc4..8527da58c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.9.3",
+  "version": "0.9.4",
   "description": "Serves JSON files through REST routes.",
   "main": "./lib/server/index.js",
   "bin": "./bin/index.js",
From 7c402a855665713c131dd14e72dc25eb0a62f417 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Wed, 7 Dec 2016 09:43:34 +0100
Subject: [PATCH 061/494] Update package.json
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 8527da58c..c6216dfc4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.9.4",
+  "version": "0.9.3",
   "description": "Serves JSON files through REST routes.",
   "main": "./lib/server/index.js",
   "bin": "./bin/index.js",
From 202a4160980361e025e952c4b8f27a1404f24d5a Mon Sep 17 00:00:00 2001
From: Ahmed Ayoub 
Date: Thu, 8 Dec 2016 22:53:16 +0100
Subject: [PATCH 062/494] update req.query when rewrite without params (#432)
* update req.query when rewrite without params #431
* add tests for rewrite rules with query and without paramas for PR #432
* [typo] add tests for rewrite rules with query and without paramas for PR #432
---
 src/server/rewriter.js | 10 +++++-----
 test/server/plural.js  | 13 ++++++++++++-
 2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/server/rewriter.js b/src/server/rewriter.js
index 718220f37..a48e91069 100644
--- a/src/server/rewriter.js
+++ b/src/server/rewriter.js
@@ -1,7 +1,9 @@
 const express = require('express')
 const url = require('url')
 const _ = require('lodash')
-
+function updateQueryString(target,sourceUrl) {
+  return !!~sourceUrl.indexOf('?') ? _.assign(target, url.parse(sourceUrl, true).query) : {};
+}
 module.exports = (routes) => {
   const router = express.Router()
 
@@ -14,16 +16,14 @@ module.exports = (routes) => {
           target = target.replace(':' + param, req.params[param])
         }
         req.url = target
-        if (target.indexOf('?')) {
-          // create query from target
-          _.assign(req.query, url.parse(target, true).query)
-        }
+        req.query = updateQueryString(req.query,req.url)
         next()
       })
     } else {
       router.all(route + '*', (req, res, next) => {
         // Rewrite url by replacing prefix
         req.url = req.url.replace(route, routes[route])
+        req.query = updateQueryString(req.query,req.url)
         next()
       })
     }
diff --git a/test/server/plural.js b/test/server/plural.js
index 9a0918b04..25103b67d 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -78,7 +78,9 @@ describe('Server', () => {
     server.use(jsonServer.rewriter({
       '/api/': '/',
       '/blog/posts/:id/show': '/posts/:id',
-      '/comments/special/:userId-:body': '/comments/?userId=:userId&body=:body'
+      '/comments/special/:userId-:body': '/comments/?userId=:userId&body=:body',
+      '/firstpostwithcomments': '/posts/1?_embed=comments'
+
     }))
     server.use(router)
   })
@@ -686,6 +688,15 @@ describe('Server', () => {
         .end(done)
     })
 
+    it('should rewrite using query without params', function (done) {
+      const expectedPost = _.cloneDeep(db.posts[0])
+      expectedPost.comments = [ db.comments[0], db.comments[1] ]
+      request(server)
+        .get('/firstpostwithcomments')
+        .expect(expectedPost)
+        .end(done)
+    })
+
     it('should rewrite using params and query', function (done) {
       request(server)
         .get('/comments/special/1-quux')
From 760c37d288dfbe3ba4a18b24036de1eb31324292 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 8 Dec 2016 22:55:35 +0100
Subject: [PATCH 063/494] Update CHANGELOG.md
---
 CHANGELOG.md | 4 ++++
 1 file changed, 4 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 89ce05272..a87051abc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Change Log
 
+## [0.9.4][2016-12-08]
+
+* Improve rewriter [#431](https://github.com/typicode/json-server/issues/431)
+
 ## [0.9.3][2016-12-07]
 
 * Fix [#396](https://github.com/typicode/json-server/issues/396) PUT/PATCH saves the updated item with an id that has been converted to string
From 0bac0352587ff58ac494b6390840f4309a75de82 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 8 Dec 2016 23:29:43 +0100
Subject: [PATCH 064/494] Update
---
 package.json           |  1 +
 src/cli/run.js         | 22 ++++++++++++++--------
 src/server/rewriter.js |  8 ++++----
 3 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/package.json b/package.json
index c6216dfc4..d574c5179 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
     "cors": "^2.3.0",
     "errorhandler": "^1.2.0",
     "express": "^4.9.5",
+    "json-parse-helpfulerror": "^1.0.3",
     "lodash": "^4.11.2",
     "lowdb": "^0.14.0",
     "method-override": "^2.1.2",
diff --git a/src/cli/run.js b/src/cli/run.js
index fc78cfd22..a67d7303b 100644
--- a/src/cli/run.js
+++ b/src/cli/run.js
@@ -1,5 +1,6 @@
 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')
@@ -189,25 +190,30 @@ module.exports = function (argv) {
       // Watch .js or .json file
       // Since lowdb uses atomic writing, directory is watched instead of file
       const watchedDir = path.dirname(source)
+      let readError = false
       fs.watch(watchedDir, (event, file) => {
-<<<<<<< HEAD
         // https://github.com/typicode/json-server/issues/420
         // file can be null
         if (file) {
           const watchedFile = path.resolve(watchedDir, file)
           if (watchedFile === path.resolve(source)) {
             if (is.JSON(watchedFile)) {
-              var obj
+              let obj
               try {
-                obj = JSON.parse(fs.readFileSync(watchedFile))
+                obj = jph.parse(fs.readFileSync(watchedFile))
+                if (readError) {
+                  console.log(chalk.green(`  Read error has been fixed :)`))
+                  readError = false
+                }
               } catch (e) {
-                console.log('Error reading JSON file');
-                console.dir(e);
-                return;
+                readError = true
+                console.log(chalk.red(`  Error reading ${watchedFile}`))
+                console.error(e.message)
+                return
               }
-              
+
               // Compare .json file content with in memory database
-              var isDatabaseDifferent = !_.isEqual(obj, app.db.getState())
+              const isDatabaseDifferent = !_.isEqual(obj, app.db.getState())
               if (isDatabaseDifferent) {
                 console.log(chalk.gray(`  ${source} has changed, reloading...`))
                 server && server.destroy()
diff --git a/src/server/rewriter.js b/src/server/rewriter.js
index a48e91069..e94ceb90e 100644
--- a/src/server/rewriter.js
+++ b/src/server/rewriter.js
@@ -1,8 +1,8 @@
 const express = require('express')
 const url = require('url')
 const _ = require('lodash')
-function updateQueryString(target,sourceUrl) {
-  return !!~sourceUrl.indexOf('?') ? _.assign(target, url.parse(sourceUrl, true).query) : {};
+function updateQueryString (target, sourceUrl) {
+  return ~sourceUrl.indexOf('?') ? _.assign(target, url.parse(sourceUrl, true).query) : {}
 }
 module.exports = (routes) => {
   const router = express.Router()
@@ -16,14 +16,14 @@ module.exports = (routes) => {
           target = target.replace(':' + param, req.params[param])
         }
         req.url = target
-        req.query = updateQueryString(req.query,req.url)
+        req.query = updateQueryString(req.query, req.url)
         next()
       })
     } else {
       router.all(route + '*', (req, res, next) => {
         // Rewrite url by replacing prefix
         req.url = req.url.replace(route, routes[route])
-        req.query = updateQueryString(req.query,req.url)
+        req.query = updateQueryString(req.query, req.url)
         next()
       })
     }
From 2960b273376772b2479f488cf6915cad155e975a Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 8 Dec 2016 23:30:13 +0100
Subject: [PATCH 065/494] Update
---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 0c475f8ea..306cc31e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ tmp
 lib
 .DS_Store
 .idea
+db.json
\ No newline at end of file
From 47e76434103b87cf3550650b01bcca25fd11dbe5 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 8 Dec 2016 23:41:52 +0100
Subject: [PATCH 066/494] Update CHANGELOG.md
---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a87051abc..0c99e38ca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 ## [0.9.4][2016-12-08]
 
 * Improve rewriter [#431](https://github.com/typicode/json-server/issues/431)
+* Improve watch mode [#427](https://github.com/typicode/json-server/pull/427) 
 
 ## [0.9.3][2016-12-07]
 
From 442746efcc5c7fb9cb6453f649e33c7a256260ff Mon Sep 17 00:00:00 2001
From: typicode 
Date: Thu, 8 Dec 2016 23:47:41 +0100
Subject: [PATCH 067/494] 0.9.4
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index d574c5179..fa5c23b5f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "json-server",
-  "version": "0.9.3",
+  "version": "0.9.4",
   "description": "Serves JSON files through REST routes.",
   "main": "./lib/server/index.js",
   "bin": "./bin/index.js",
From bb64e719b71a048d1f8a03e9724a167cb8d6abb5 Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sun, 25 Dec 2016 07:44:36 +0100
Subject: [PATCH 068/494] Update rewriter
---
 src/server/rewriter.js |  4 ++++
 test/server/plural.js  | 21 ++++++++++++++-------
 2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/src/server/rewriter.js b/src/server/rewriter.js
index e94ceb90e..d7f3c7471 100644
--- a/src/server/rewriter.js
+++ b/src/server/rewriter.js
@@ -7,6 +7,10 @@ function updateQueryString (target, sourceUrl) {
 module.exports = (routes) => {
   const router = express.Router()
 
+  router.get('/__rules', (req, res) => {
+    res.json(routes)
+  })
+
   Object.keys(routes).forEach((route) => {
     if (route.indexOf(':') !== -1) {
       router.all(route, (req, res, next) => {
diff --git a/test/server/plural.js b/test/server/plural.js
index 25103b67d..8a70ec8a4 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -7,6 +7,12 @@ describe('Server', () => {
   let server
   let router
   let db
+  const rewriterRules = {
+    '/api/': '/',
+    '/blog/posts/:id/show': '/posts/:id',
+    '/comments/special/:userId-:body': '/comments/?userId=:userId&body=:body',
+    '/firstpostwithcomments': '/posts/1?_embed=comments'
+  }
 
   beforeEach(() => {
     db = {}
@@ -75,13 +81,7 @@ describe('Server', () => {
     server = jsonServer.create()
     router = jsonServer.router(db)
     server.use(jsonServer.defaults())
-    server.use(jsonServer.rewriter({
-      '/api/': '/',
-      '/blog/posts/:id/show': '/posts/:id',
-      '/comments/special/:userId-:body': '/comments/?userId=:userId&body=:body',
-      '/firstpostwithcomments': '/posts/1?_embed=comments'
-
-    }))
+    server.use(jsonServer.rewriter(rewriterRules))
     server.use(router)
   })
 
@@ -703,6 +703,13 @@ describe('Server', () => {
         .expect([db.comments[4]])
         .end(done)
     })
+
+    it('should expose routes', (done) => {
+      request(server)
+        .get('/__rules')
+        .expect(rewriterRules)
+        .end(done)
+    })
   })
 
   describe('router.render', (done) => {
From ad9cbdd1ae4c68c1909c4d938285d1d3fc9d5d0d Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sun, 25 Dec 2016 18:49:09 +0100
Subject: [PATCH 069/494] Add failing test
---
 test/server/plural.js | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/test/server/plural.js b/test/server/plural.js
index 8a70ec8a4..a144ca617 100644
--- a/test/server/plural.js
+++ b/test/server/plural.js
@@ -11,7 +11,8 @@ describe('Server', () => {
     '/api/': '/',
     '/blog/posts/:id/show': '/posts/:id',
     '/comments/special/:userId-:body': '/comments/?userId=:userId&body=:body',
-    '/firstpostwithcomments': '/posts/1?_embed=comments'
+    '/firstpostwithcomments': '/posts/1?_embed=comments',
+    '/articles?_id=:id': '/posts/:id'
   }
 
   beforeEach(() => {
@@ -704,6 +705,14 @@ describe('Server', () => {
         .end(done)
     })
 
+    // TODO
+    // it('should rewrite query params', (done) => {
+    //   request(server)
+    //     .get('/articles?_id=1')
+    //     .expect(db.posts[0])
+    //     .end(done)
+    // })
+
     it('should expose routes', (done) => {
       request(server)
         .get('/__rules')
From 69321be00fe85d026a88e7f30d464bd51afcee2f Mon Sep 17 00:00:00 2001
From: typicode 
Date: Sun, 25 Dec 2016 19:12:38 +0100
Subject: [PATCH 070/494] Display custom routes
---
 package.json                 |  2 +-
 src/server/public/index.html | 29 ++++++++++++++++++++++-------
 2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/package.json b/package.json
index fa5c23b5f..6ef35be00 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
     "test": "npm run test:cli && npm run test:server && standard --fix",
     "test:cli": "npm run build && cross-env NODE_ENV=test mocha test/cli/*.js",
     "test:server": "cross-env NODE_ENV=test mocha test/server/*.js",
-    "start": "node bin",
+    "start": "babel-node src/cli/bin",
     "prepush": "npm t",
     "build": "babel src -d lib --copy-files",
     "toc": "markdown-toc -i README.md",
diff --git a/src/server/public/index.html b/src/server/public/index.html
index bdac2a7ad..83a644b90 100644
--- a/src/server/public/index.html
+++ b/src/server/public/index.html
@@ -27,7 +27,9 @@ Routes
         Here are the resources that JSON Server has loaded:
       
       
-      
+
+      
+
       
         You can view database current state at any time:
       
@@ -36,10 +38,10 @@ Routes
           db
         
       
-      
+
       
         You can use any HTTP verbs (GET, POST, PUT, PATCH and DELETE) and access your resources from anywhere
-        using CORS and JSONP.
+        using CORS or JSONP.
       
 
       Documentation
@@ -61,17 +63,30 @@ Issues
       
     
 
-
     
     
-    
+    
+