mirror of
https://github.com/typicode/json-server.git
synced 2025-07-28 20:52:08 +08:00
Update
This commit is contained in:
62
README.md
62
README.md
@ -1,7 +1,6 @@
|
|||||||
[](https://travis-ci.org/typicode/json-server)
|
<p align="center">
|
||||||
[](http://badge.fury.io/js/json-server)
|
<img height="56" width="64" src="http://i.imgur.com/JCxrqRw.png"/>
|
||||||
|
</p>
|
||||||

|
|
||||||
|
|
||||||
# JSON Server
|
# JSON Server
|
||||||
|
|
||||||
@ -9,36 +8,43 @@ Give it a JSON or JS seed file and it will serve it through REST routes.
|
|||||||
|
|
||||||
Created with :heart: for front-end developers who need a flexible back-end for quick prototyping and mocking.
|
Created with :heart: for front-end developers who need a flexible back-end for quick prototyping and mocking.
|
||||||
|
|
||||||
|
[](https://travis-ci.org/typicode/json-server)
|
||||||
|
[](http://badge.fury.io/js/json-server)
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Command line interface
|
### Command line interface
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cat db.json
|
$ json-server --file db.json
|
||||||
|
$ curl -i http://localhost:3000/posts/1
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// db.json
|
||||||
{
|
{
|
||||||
"posts": [
|
"posts": [
|
||||||
{ "id": 1, "body": "foo" }
|
{ "id": 1, "body": "foo" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
$ json-server --file db.json
|
|
||||||
$ curl -i http://localhost:3000/posts/1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You can type 's' at any moment to save the current live JSON object to timestamped
|
|
||||||
file.
|
|
||||||
|
|
||||||
### Node module
|
### Node module
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var server = require('json-server');
|
var server = require('json-server');
|
||||||
|
|
||||||
var db = {
|
server.low.db = {
|
||||||
posts: [
|
posts: [
|
||||||
{ id: 1, body: 'foo' }
|
{ id: 1, body: 'foo' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
server.run(db);
|
server.get('/another/route', function(req, res, next) {
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
|
||||||
|
server.listen(3000);
|
||||||
```
|
```
|
||||||
|
|
||||||
You can find a running demo here: http://jsonplaceholder.typicode.com.
|
You can find a running demo here: http://jsonplaceholder.typicode.com.
|
||||||
@ -58,38 +64,25 @@ You can find a running demo here: http://jsonplaceholder.typicode.com.
|
|||||||
$ npm install -g json-server
|
$ npm install -g json-server
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Command line interface
|
### Command line interface
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
json-server --help
|
|
||||||
|
|
||||||
Usage: json-server [options]
|
Usage: json-server <source> [options]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
-h, --help output usage information
|
--version output version
|
||||||
-V, --version output the version number
|
--port <port> set port
|
||||||
-f --file <file> load db from a js or json file
|
|
||||||
-u --url <url> load db from a URL
|
|
||||||
-p --port [port] server port
|
|
||||||
--read-only read only mode
|
|
||||||
```
|
|
||||||
|
|
||||||
JSON Server can load JSON from multiple sources:
|
Exemples:
|
||||||
|
|
||||||
```bash
|
json-server db.json
|
||||||
$ json-server --file db.json
|
json-server seed.js
|
||||||
$ json-server --file seed.js
|
json-server http://example.com/db.json
|
||||||
$ json-server --url http://example.com/db.json
|
|
||||||
```
|
|
||||||
|
|
||||||
And be run in read-only mode (useful if deployed on a public server):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ json-server --file db.json --read-only
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Input
|
#### Input
|
||||||
@ -129,7 +122,6 @@ JSON Server expects JS files to export a ```run``` method that returns an object
|
|||||||
|
|
||||||
Seed files are useful if you need to programmaticaly create a lot of data.
|
Seed files are useful if you need to programmaticaly create a lot of data.
|
||||||
|
|
||||||
|
|
||||||
### Node module
|
### Node module
|
||||||
|
|
||||||
#### run(db, [options])
|
#### run(db, [options])
|
||||||
@ -149,7 +141,7 @@ By default, ```port``` is set to 3000 and ```readOnly``` to false.
|
|||||||
|
|
||||||
```
|
```
|
||||||
GET /:resource
|
GET /:resource
|
||||||
GET /:resource?attr=&attr=&
|
GET /:resource?filter=&filter=&
|
||||||
GET /:parent/:parentId/:resource
|
GET /:parent/:parentId/:resource
|
||||||
GET /:resource/:id
|
GET /:resource/:id
|
||||||
POST /:resource
|
POST /:resource
|
||||||
@ -189,4 +181,4 @@ $ npm test
|
|||||||
|
|
||||||
## Articles
|
## Articles
|
||||||
|
|
||||||
[Fast prototyping using Restangular and Json-server](http://bahmutov.calepin.co/fast-prototyping-using-restangular-and-json-server.html)
|
* [Fast prototyping using Restangular and Json-server](http://bahmutov.calepin.co/fast-prototyping-using-restangular-and-json-server.html)
|
||||||
|
11
bin/index.js
Normal file
11
bin/index.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
var minimist = require('minimist')
|
||||||
|
var updateNotifier = require('update-notifier')
|
||||||
|
var cli = require('../src/cli')
|
||||||
|
|
||||||
|
var notifier = updateNotifier({packagePath: '../package'})
|
||||||
|
if (notifier.update) notifier.notify()
|
||||||
|
|
||||||
|
var argv = minimist(process.argv.slice(2))
|
||||||
|
|
||||||
|
cli.run(argv)
|
20
db.json
Normal file
20
db.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"posts": [
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"body": "bar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"comments": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"published": true,
|
||||||
|
"postId": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"published": false,
|
||||||
|
"postId": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -2,8 +2,8 @@
|
|||||||
"name": "json-server",
|
"name": "json-server",
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"description": "Serves JSON files through REST routes.",
|
"description": "Serves JSON files through REST routes.",
|
||||||
"main": "server.js",
|
"main": "./src/server.js",
|
||||||
"bin": "./bin/cli.js",
|
"bin": "./bin/index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
"test": "test"
|
"test": "test"
|
||||||
},
|
},
|
||||||
@ -15,7 +15,9 @@
|
|||||||
"underscore.inflections": "~0.2.1",
|
"underscore.inflections": "~0.2.1",
|
||||||
"low": "^0.4.2",
|
"low": "^0.4.2",
|
||||||
"yargs": "^1.2.1",
|
"yargs": "^1.2.1",
|
||||||
"chalk": "^0.4.0"
|
"chalk": "^0.4.0",
|
||||||
|
"minimist": "0.0.8",
|
||||||
|
"update-notifier": "^0.1.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"supertest": "~0.8.1",
|
"supertest": "~0.8.1",
|
||||||
|
@ -1,66 +1,87 @@
|
|||||||
|
var fs = require('fs')
|
||||||
var chalk = require('chalk')
|
var chalk = require('chalk')
|
||||||
var request = require('request')
|
var minimist = require('minimist')
|
||||||
|
var request = require('superagent')
|
||||||
var low = require('low')
|
var low = require('low')
|
||||||
var server = require('./server')
|
var server = require('./server')
|
||||||
|
|
||||||
function hello() {
|
// Output version
|
||||||
console.log(
|
function version() {
|
||||||
chalk.green('\n{^ ^} Heya!\n')
|
var pkg = require('../package.json')
|
||||||
)
|
console.log(pkg.version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output help.txt with some colors
|
||||||
|
function help() {
|
||||||
|
var txt = fs.readFileSync(__dirname + '/help.txt').toString()
|
||||||
|
txt = txt.replace(/json-server/g, chalk.green('json-server'))
|
||||||
|
console.log(txt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start server
|
||||||
function start(port) {
|
function start(port) {
|
||||||
for (var prop in low.db) {
|
for (var prop in low.db) {
|
||||||
console.log('http://localhost:' + port + '/' + chalk.green(prop))
|
console.log('http://localhost:' + port + '/' + chalk.green(prop))
|
||||||
}
|
}
|
||||||
|
|
||||||
server.listen(port)
|
|
||||||
}
|
|
||||||
|
|
||||||
function run(argv) {
|
|
||||||
hello();
|
|
||||||
|
|
||||||
var source = argv._[0]
|
|
||||||
|
|
||||||
console.log('Loading database from ' + source + '\n')
|
|
||||||
|
|
||||||
if (/\.json$/.test(source)) {
|
|
||||||
var path = process.cwd() + '/' + source
|
|
||||||
low.path = path
|
|
||||||
low.db = require(path);
|
|
||||||
start(argv.port)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/\.js$/.test(source)) {
|
|
||||||
var path = process.cwd() + '/' + source
|
|
||||||
low.db = require(path).run();
|
|
||||||
start(argv.port)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/^http/.test(source)) {
|
|
||||||
request.get(source)
|
|
||||||
.end(function(err, res) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err)
|
|
||||||
} else {
|
|
||||||
low.db = JSON.parse(res.text)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
start(argv.port)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
'\nEnter ' + chalk.green('`s`') + ' at any time to create a snapshot of the db\n'
|
'\nEnter ' + chalk.green('`s`') + ' at any time to create a snapshot of the db\n'
|
||||||
)
|
)
|
||||||
process.stdin.resume()
|
process.stdin.resume()
|
||||||
process.stdin.setEncoding('utf8')
|
process.stdin.setEncoding('utf8')
|
||||||
|
|
||||||
process.stdin.on('data', function (chunk) {
|
process.stdin.on('data', function (chunk) {
|
||||||
if (chunk.trim().toLowerCase() === 's') {
|
if (chunk.trim().toLowerCase() === 's') {
|
||||||
low.save('db-' + Date.now() + '.json')
|
var file = 'db-' + Date.now() + '.json'
|
||||||
|
low.save(file)
|
||||||
|
console.log('\nSaved snapshot to ' + chalk.green(file) + '\n')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
server.listen(port)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load source
|
||||||
|
function load(source, port) {
|
||||||
|
console.log(chalk.green('\n{^ ^} Heya!\n'))
|
||||||
|
|
||||||
|
console.log('Loading database from ' + source + '\n')
|
||||||
|
|
||||||
|
if (/\.json$/.test(source)) {
|
||||||
|
var path = process.cwd() + '/' + source
|
||||||
|
low.path = path
|
||||||
|
low.db = require(path);
|
||||||
|
start(port)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/\.js$/.test(source)) {
|
||||||
|
var path = process.cwd() + '/' + source
|
||||||
|
low.db = require(path).run();
|
||||||
|
start(port)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^http/.test(source)) {
|
||||||
|
request
|
||||||
|
.get(source)
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err)
|
||||||
|
} else {
|
||||||
|
low.db = JSON.parse(res.text)
|
||||||
|
start(port)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses minimist parsed argv
|
||||||
|
function run(argv) {
|
||||||
|
var source = argv._[0]
|
||||||
|
var port = argv.port || 3000
|
||||||
|
|
||||||
|
if (argv.version) return version()
|
||||||
|
if (source) return load(source, port)
|
||||||
|
|
||||||
|
help()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.run = run
|
module.exports.run = run
|
14
src/help.txt
Normal file
14
src/help.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
Usage: json-server <source> [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
--version output version
|
||||||
|
--port <port> set port
|
||||||
|
|
||||||
|
Exemples:
|
||||||
|
|
||||||
|
json-server db.json
|
||||||
|
json-server seed.js
|
||||||
|
json-server http://example.com/db.json
|
||||||
|
|
81
src/routes.js
Normal file
81
src/routes.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
var _ = require('underscore')
|
||||||
|
var low = require('low')
|
||||||
|
var utils = require('./utils')
|
||||||
|
|
||||||
|
var routes = {}
|
||||||
|
|
||||||
|
// GET /db
|
||||||
|
routes.db = function(req, res, next) {
|
||||||
|
res.jsonp(low.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /:resource?attr=&attr=
|
||||||
|
// GET /:parent/:parentId/:resource
|
||||||
|
routes.list = function(req, res, next) {
|
||||||
|
var props = {}
|
||||||
|
var resource
|
||||||
|
|
||||||
|
var _start = req.query._start
|
||||||
|
var _end = req.query._end
|
||||||
|
|
||||||
|
delete req.query._start
|
||||||
|
delete req.query._end
|
||||||
|
|
||||||
|
if (req.params.parent) {
|
||||||
|
props[req.params.parent.slice(0, - 1) + 'Id'] = +req.params.parentId
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var key in req.query) {
|
||||||
|
props[key] = utils.toNative(req.query[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_(props).isEmpty()) {
|
||||||
|
resource = low(req.params.resource).value()
|
||||||
|
} else {
|
||||||
|
resource = low(req.params.resource).where(props).value()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_start) {
|
||||||
|
resource = resource.slice(_start, _end)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.jsonp(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /:resource/:id
|
||||||
|
routes.show = function(req, res, next) {
|
||||||
|
var resource = low(req.params.resource)
|
||||||
|
.get(+req.params.id)
|
||||||
|
.value()
|
||||||
|
|
||||||
|
res.jsonp(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /:resource
|
||||||
|
routes.create = function(req, res, next) {
|
||||||
|
var resource = low(req.params.resource)
|
||||||
|
.insert(req.body)
|
||||||
|
.value()
|
||||||
|
|
||||||
|
res.jsonp(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT /:resource/:id
|
||||||
|
// PATCH /:resource/:id
|
||||||
|
routes.update = function(req, res, next) {
|
||||||
|
var resource = low(req.params.resource)
|
||||||
|
.update(+req.params.id, req.body)
|
||||||
|
.value()
|
||||||
|
|
||||||
|
res.jsonp(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE /:resource/:id
|
||||||
|
routes.destroy = function(req, res, next) {
|
||||||
|
low(req.params.resource).remove(+req.params.id)
|
||||||
|
utils.clean()
|
||||||
|
|
||||||
|
res.send(204)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = routes
|
102
src/server.js
102
src/server.js
@ -1,9 +1,10 @@
|
|||||||
var express = require('express')
|
var express = require('express')
|
||||||
|
var cors = require('cors')
|
||||||
var http = require('http')
|
var http = require('http')
|
||||||
var path = require('path')
|
var path = require('path')
|
||||||
var _ = require('underscore')
|
|
||||||
var low = require('low')
|
var low = require('low')
|
||||||
var utils = require('./utils')
|
var utils = require('./utils')
|
||||||
|
var routes = require('./routes')
|
||||||
|
|
||||||
low._.createId = utils.createId
|
low._.createId = utils.createId
|
||||||
|
|
||||||
@ -15,104 +16,25 @@ server.use(express.json())
|
|||||||
server.use(express.urlencoded())
|
server.use(express.urlencoded())
|
||||||
server.use(express.methodOverride())
|
server.use(express.methodOverride())
|
||||||
server.use(express.static(path.join(__dirname, '../public')))
|
server.use(express.static(path.join(__dirname, '../public')))
|
||||||
|
server.use(cors())
|
||||||
server.use(server.router)
|
server.use(server.router)
|
||||||
|
|
||||||
if ('development' == server.get('env')) {
|
if ('development' == server.get('env')) {
|
||||||
server.use(express.errorHandler());
|
server.use(express.errorHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
routes = {}
|
server.get( '/db' , routes.db)
|
||||||
|
server.get( '/:resource' , routes.list)
|
||||||
|
server.get( '/:parent/:parentId/:resource' , routes.list)
|
||||||
|
server.get( '/:resource/:id' , routes.show)
|
||||||
|
|
||||||
// GET /db
|
server.post( '/:resource' , routes.create)
|
||||||
routes.db = function(req, res, next) {
|
|
||||||
res.jsonp(low.db)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET /:resource?attr=&attr=
|
server.put( '/:resource/:id' , routes.update)
|
||||||
routes.list = function(req, res, next) {
|
server.patch('/:resource/:id' , routes.update)
|
||||||
var properties = {}
|
|
||||||
var query
|
|
||||||
|
|
||||||
Object.keys(req.query).forEach(function (key) {
|
server.del( '/:resource/:id' , routes.destroy)
|
||||||
var value = req.query[key]
|
|
||||||
properties[key] = utils.toNative(value)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (_(properties).isEmpty()) {
|
server.low = low
|
||||||
query = low(req.params.resource)
|
|
||||||
} else {
|
|
||||||
query = low(req.params.resource).where(properties)
|
|
||||||
}
|
|
||||||
|
|
||||||
res.jsonp(query.value())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET /:parent/:parentId/:resource
|
|
||||||
routes.nestedList = function(req, res, next) {
|
|
||||||
var properties = {}
|
|
||||||
var resource
|
|
||||||
|
|
||||||
// Set parentID
|
|
||||||
properties[req.params.parent.slice(0, - 1) + 'Id'] = +req.params.parentId
|
|
||||||
|
|
||||||
// Filter using parentID
|
|
||||||
resource = low(req.params.resource)
|
|
||||||
.where(properties)
|
|
||||||
.value()
|
|
||||||
|
|
||||||
res.jsonp(resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET /:resource/:id
|
|
||||||
routes.show = function(req, res, next) {
|
|
||||||
var resource = low(req.params.resource)
|
|
||||||
.get(+req.params.id)
|
|
||||||
.value()
|
|
||||||
|
|
||||||
res.jsonp(resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST /:resource
|
|
||||||
routes.create = function(req, res, next) {
|
|
||||||
var resource = low(req.params.resource)
|
|
||||||
.insert(req.body)
|
|
||||||
.value()
|
|
||||||
|
|
||||||
res.jsonp(resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT /:resource/:id
|
|
||||||
// PATCH /:resource/:id
|
|
||||||
routes.update = function(req, res, next) {
|
|
||||||
var resource = low(req.params.resource)
|
|
||||||
.update(+req.params.id, req.body)
|
|
||||||
.value()
|
|
||||||
|
|
||||||
res.jsonp(resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE /:resource/:id
|
|
||||||
routes.destroy = function(req, res, next) {
|
|
||||||
low(req.params.resource).remove(+req.params.id)
|
|
||||||
utils.clean()
|
|
||||||
|
|
||||||
res.send(204)
|
|
||||||
}
|
|
||||||
|
|
||||||
server.get('/db', routes.db)
|
|
||||||
server.get('/:resource', routes.list)
|
|
||||||
server.get('/:parent/:parentId/:resource', routes.nestedList)
|
|
||||||
server.get('/:resource/:id', routes.show)
|
|
||||||
server.post('/:resource', routes.create)
|
|
||||||
server.put('/:resource/:id', routes.update)
|
|
||||||
server.patch('/:resource/:id', routes.update)
|
|
||||||
server.del('/:resource/:id', routes.destroy)
|
|
||||||
|
|
||||||
server.on('after', function (req, res, route, err) {
|
|
||||||
var latency = Date.now() - req.time()
|
|
||||||
console.log('%s %s %s - %sms',
|
|
||||||
req.method, req.url, res.statusCode, latency
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = server
|
module.exports = server
|
@ -52,6 +52,16 @@ describe('Server', function() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe.only('GET /:resource?_start=&_end=', function() {
|
||||||
|
it('should respond with sliced array', function(done) {
|
||||||
|
request(server)
|
||||||
|
.get('/comments?_start=1&_end=2')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(low.db.comments.slice(1, 2))
|
||||||
|
.expect(200, done)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('GET /:parent/:parentId/:resource', function() {
|
describe('GET /:parent/:parentId/:resource', function() {
|
||||||
it('should respond with json and corresponding nested resources', function(done) {
|
it('should respond with json and corresponding nested resources', function(done) {
|
||||||
request(server)
|
request(server)
|
||||||
|
Reference in New Issue
Block a user