mirror of
https://github.com/typicode/json-server.git
synced 2025-08-01 09:13:32 +08:00
Merge branch 'expand-resources' of https://github.com/adamsea/json-server into adamsea-expand-resources
Conflicts: src/router.js test/server/plural.js
This commit is contained in:
13
README.md
13
README.md
@ -6,7 +6,7 @@ Created with <3 for front-end developers who need a quick back-end for prototypi
|
|||||||
|
|
||||||
* [Egghead.io free video tutorial - Creating demo APIs with json-server](https://egghead.io/lessons/nodejs-creating-demo-apis-with-json-server)
|
* [Egghead.io free video tutorial - Creating demo APIs with json-server](https://egghead.io/lessons/nodejs-creating-demo-apis-with-json-server)
|
||||||
* [JSONPlaceholder - Live running version](http://jsonplaceholder.typicode.com)
|
* [JSONPlaceholder - Live running version](http://jsonplaceholder.typicode.com)
|
||||||
|
|
||||||
_See also [hotel](https://github.com/typicode/hotel), a simple process manager for developers._
|
_See also [hotel](https://github.com/typicode/hotel), a simple process manager for developers._
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
@ -70,6 +70,7 @@ To slice resources, add `_start` and `_end` or `_limit` (an `X-Total-Count` head
|
|||||||
```
|
```
|
||||||
GET /posts?_start=20&_end=30
|
GET /posts?_start=20&_end=30
|
||||||
GET /posts/1/comments?_start=20&_end=30
|
GET /posts/1/comments?_start=20&_end=30
|
||||||
|
GET /posts/1/comments?_start=20&_limit=10
|
||||||
```
|
```
|
||||||
|
|
||||||
To sort resources, add `_sort` and `_order` (ascending order by default).
|
To sort resources, add `_sort` and `_order` (ascending order by default).
|
||||||
@ -85,12 +86,18 @@ To make a full-text search on resources, add `q`.
|
|||||||
GET /posts?q=internet
|
GET /posts?q=internet
|
||||||
```
|
```
|
||||||
|
|
||||||
To embed other resources, add `_embed`.
|
To embed resources, add `_embed`.
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /posts/1?_embed=comments
|
GET /posts/1?_embed=comments
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To expand inner resources, add `_expand`.
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /comments/1?_expand=post
|
||||||
|
```
|
||||||
|
|
||||||
Returns database.
|
Returns database.
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -205,7 +212,7 @@ To modify responses, use `router.render()`:
|
|||||||
router.render = function (req, res) {
|
router.render = function (req, res) {
|
||||||
res.jsonp({
|
res.jsonp({
|
||||||
body: res.locals.data
|
body: res.locals.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@ module.exports = function (db, name) {
|
|||||||
// Create router
|
// Create router
|
||||||
var router = express.Router()
|
var router = express.Router()
|
||||||
|
|
||||||
// GET /:resource
|
// GET /name
|
||||||
// GET /:resource?q=
|
// GET /name?q=
|
||||||
// GET /:resource?attr=&attr=
|
// GET /name?attr=&attr=
|
||||||
// GET /:resource?_end=&*
|
// GET /name?_end=&*
|
||||||
// GET /:resource?_start=&_end=&*
|
// GET /name?_start=&_end=&*
|
||||||
function list (req, res, next) {
|
function list (req, res, next) {
|
||||||
|
|
||||||
// Filters list
|
// Filters list
|
||||||
@ -103,33 +103,51 @@ module.exports = function (db, name) {
|
|||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /:resource/:id
|
// GET /name/:id
|
||||||
|
// GET /name/:id?_embed=&_expand
|
||||||
function show (req, res, next) {
|
function show (req, res, next) {
|
||||||
var _embed = req.query._embed
|
var _embed = req.query._embed
|
||||||
|
var _expand = req.query._expand
|
||||||
var id = utils.toNative(req.params.id)
|
var id = utils.toNative(req.params.id)
|
||||||
var resource = db(name)
|
var resource = db(name).getById(id)
|
||||||
.getById(id)
|
|
||||||
|
// Filter empty params
|
||||||
|
function filter (p) {
|
||||||
|
return p && p.trim().length > 0
|
||||||
|
}
|
||||||
|
|
||||||
if (resource) {
|
if (resource) {
|
||||||
// Clone resource to avoid making changes to the underlying object
|
// Clone resource to avoid making changes to the underlying object
|
||||||
resource = _.cloneDeep(resource)
|
resource = _.cloneDeep(resource)
|
||||||
|
|
||||||
// Always use an array
|
// Always use an array
|
||||||
_embed = _.isArray(_embed) ? _embed : [_embed]
|
_embed = [].concat(_embed)
|
||||||
|
_expand = [].concat(_expand)
|
||||||
|
|
||||||
// Embed other resources based on resource id
|
// Embed other resources based on resource id
|
||||||
_embed.forEach(function (otherResource) {
|
// /posts/1?_embed=comments
|
||||||
|
_embed
|
||||||
|
.filter(filter)
|
||||||
|
.forEach(function (otherResource) {
|
||||||
|
if (db.object[otherResource]) {
|
||||||
|
var query = {}
|
||||||
|
var singularResource = pluralize.singular(name)
|
||||||
|
query[singularResource + 'Id'] = id
|
||||||
|
resource[otherResource] = db(otherResource).where(query)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if (otherResource
|
// Expand inner resources based on id
|
||||||
&& otherResource.trim().length > 0
|
// /posts/1?_expand=user
|
||||||
&& db.object[otherResource]) {
|
_expand
|
||||||
|
.filter(filter)
|
||||||
var query = {}
|
.forEach(function (innerResource) {
|
||||||
var prop = pluralize.singular(name) + 'Id'
|
var plural = pluralize(innerResource)
|
||||||
query[prop] = id
|
if (db.object[plural]) {
|
||||||
resource[otherResource] = db(otherResource).where(query)
|
var prop = innerResource + 'Id'
|
||||||
|
resource[innerResource] = db(plural).getById(resource[prop])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
res.locals.data = resource
|
res.locals.data = resource
|
||||||
}
|
}
|
||||||
@ -137,7 +155,7 @@ module.exports = function (db, name) {
|
|||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /:resource
|
// POST /name
|
||||||
function create (req, res, next) {
|
function create (req, res, next) {
|
||||||
for (var key in req.body) {
|
for (var key in req.body) {
|
||||||
req.body[key] = utils.toNative(req.body[key])
|
req.body[key] = utils.toNative(req.body[key])
|
||||||
@ -151,8 +169,8 @@ module.exports = function (db, name) {
|
|||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT /:resource/:id
|
// PUT /name/:id
|
||||||
// PATCH /:resource/:id
|
// PATCH /name/:id
|
||||||
function update (req, res, next) {
|
function update (req, res, next) {
|
||||||
for (var key in req.body) {
|
for (var key in req.body) {
|
||||||
req.body[key] = utils.toNative(req.body[key])
|
req.body[key] = utils.toNative(req.body[key])
|
||||||
@ -168,7 +186,7 @@ module.exports = function (db, name) {
|
|||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE /:resource/:id
|
// DELETE /name/:id
|
||||||
function destroy (req, res, next) {
|
function destroy (req, res, next) {
|
||||||
db(name).removeById(utils.toNative(req.params.id))
|
db(name).removeById(utils.toNative(req.params.id))
|
||||||
|
|
||||||
|
@ -24,12 +24,17 @@ describe('Server', function () {
|
|||||||
{id: 3, body: 'photo'}
|
{id: 3, body: 'photo'}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
db.users = [
|
||||||
|
{id: 1, username: 'Jim'},
|
||||||
|
{id: 2, username: 'George'}
|
||||||
|
]
|
||||||
|
|
||||||
db.comments = [
|
db.comments = [
|
||||||
{id: 1, body: 'foo', published: true, postId: 1},
|
{id: 1, body: 'foo', published: true, postId: 1, userId: 1},
|
||||||
{id: 2, body: 'bar', published: false, postId: 1},
|
{id: 2, body: 'bar', published: false, postId: 1, userId: 2},
|
||||||
{id: 3, body: 'baz', published: false, postId: 2},
|
{id: 3, body: 'baz', published: false, postId: 2, userId: 1},
|
||||||
{id: 4, body: 'qux', published: true, postId: 2},
|
{id: 4, body: 'qux', published: true, postId: 2, userId: 2},
|
||||||
{id: 5, body: 'quux', published: false, postId: 2}
|
{id: 5, body: 'quux', published: false, postId: 2, userId: 1}
|
||||||
]
|
]
|
||||||
|
|
||||||
db.refs = [
|
db.refs = [
|
||||||
@ -258,6 +263,31 @@ 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]
|
||||||
|
request(server)
|
||||||
|
.get('/comments/1?_expand=post')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(comments)
|
||||||
|
.expect(200, done)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('GET /:resource/:id?_expand=&_expand=', function () {
|
||||||
|
it('should respond with corresponding resource and expanded inner resources', function (done) {
|
||||||
|
var comments = db.comments[0]
|
||||||
|
comments.post = db.posts[0]
|
||||||
|
comments.user = db.users[0]
|
||||||
|
request(server)
|
||||||
|
.get('/comments/1?_expand=post&_expand=user')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(comments)
|
||||||
|
.expect(200, done)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('POST /:resource', function () {
|
describe('POST /:resource', function () {
|
||||||
it('should respond with json, create a resource and increment id',
|
it('should respond with json, create a resource and increment id',
|
||||||
function (done) {
|
function (done) {
|
||||||
|
Reference in New Issue
Block a user