Skip to content

Commit abec949

Browse files
committed
Add route GET /resources?_embed&_expand
1 parent e088025 commit abec949

File tree

2 files changed

+100
-34
lines changed

2 files changed

+100
-34
lines changed

src/server/router/plural.js

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,37 @@ module.exports = function (db, name) {
88
// Create router
99
var router = express.Router()
1010

11+
// Embed function used in GET /name and GET /name/id
12+
function embed (resource, e) {
13+
e && [].concat(e)
14+
.forEach(function (externalResource) {
15+
if (db.object[externalResource]) {
16+
var query = {}
17+
var singularResource = pluralize.singular(name)
18+
query[singularResource + 'Id'] = resource.id
19+
resource[externalResource] = db(externalResource).where(query)
20+
}
21+
})
22+
}
23+
24+
// Expand function used in GET /name and GET /name/id
25+
function expand (resource, e) {
26+
e && [].concat(e)
27+
.forEach(function (innerResource) {
28+
var plural = pluralize(innerResource)
29+
if (db.object[plural]) {
30+
var prop = innerResource + 'Id'
31+
resource[innerResource] = db(plural).getById(resource[prop])
32+
}
33+
})
34+
}
35+
1136
// GET /name
1237
// GET /name?q=
1338
// GET /name?attr=&attr=
14-
// GET /name?_end=&*
15-
// GET /name?_start=&_end=&*
39+
// GET /name?_end=&
40+
// GET /name?_start=&_end=&
41+
// GET /name?_embed=&_expand=
1642
function list (req, res, next) {
1743

1844
// Filters list
@@ -29,12 +55,16 @@ module.exports = function (db, name) {
2955
var _sort = req.query._sort
3056
var _order = req.query._order
3157
var _limit = req.query._limit
58+
var _embed = req.query._embed
59+
var _expand = req.query._expand
3260
delete req.query.q
3361
delete req.query._start
3462
delete req.query._end
3563
delete req.query._sort
3664
delete req.query._order
3765
delete req.query._limit
66+
delete req.query._embed
67+
delete req.query._expand
3868

3969
if (q) {
4070

@@ -99,6 +129,14 @@ module.exports = function (db, name) {
99129
chain = chain.slice(_start, _start + _limit)
100130
}
101131

132+
// embed and expand
133+
chain = chain
134+
.cloneDeep()
135+
.forEach(function (element) {
136+
embed(element, _embed)
137+
expand(element, _expand)
138+
})
139+
102140
res.locals.data = chain.value()
103141
next()
104142
}
@@ -111,43 +149,17 @@ module.exports = function (db, name) {
111149
var id = utils.toNative(req.params.id)
112150
var resource = db(name).getById(id)
113151

114-
// Filter empty params
115-
function filter (p) {
116-
return p && p.trim().length > 0
117-
}
118-
119152
if (resource) {
120153
// Clone resource to avoid making changes to the underlying object
121154
resource = _.cloneDeep(resource)
122155

123-
// Always use an array
124-
_embed = [].concat(_embed)
125-
_expand = [].concat(_expand)
126-
127156
// Embed other resources based on resource id
128157
// /posts/1?_embed=comments
129-
_embed
130-
.filter(filter)
131-
.forEach(function (otherResource) {
132-
if (db.object[otherResource]) {
133-
var query = {}
134-
var singularResource = pluralize.singular(name)
135-
query[singularResource + 'Id'] = id
136-
resource[otherResource] = db(otherResource).where(query)
137-
}
138-
})
158+
embed(resource, _embed)
139159

140160
// Expand inner resources based on id
141161
// /posts/1?_expand=user
142-
_expand
143-
.filter(filter)
144-
.forEach(function (innerResource) {
145-
var plural = pluralize(innerResource)
146-
if (db.object[plural]) {
147-
var prop = innerResource + 'Id'
148-
resource[innerResource] = db(plural).getById(resource[prop])
149-
}
150-
})
162+
expand(resource, _expand)
151163

152164
res.locals.data = resource
153165
}

test/server/plural.js

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
var request = require('supertest')
21
var assert = require('assert')
2+
var _ = require('lodash')
3+
var request = require('supertest')
34
var jsonServer = require('../../src/server')
45

56
/* global beforeEach, describe, it */
@@ -38,7 +39,7 @@ describe('Server', function () {
3839
]
3940

4041
db.refs = [
41-
{id: 'abcd-1234', url: 'http://example.com/', postId: 1}
42+
{id: 'abcd-1234', url: 'http://example.com/', postId: 1, userId: 1}
4243
]
4344

4445
db.deep = [
@@ -238,8 +239,36 @@ describe('Server', function () {
238239
})
239240
})
240241

242+
describe('GET /:resource?_embed=', function () {
243+
it('should respond with corresponding resources and embedded resources', function (done) {
244+
var posts = _.cloneDeep(db.posts)
245+
posts[0].comments = [db.comments[0], db.comments[1]]
246+
posts[1].comments = [db.comments[2], db.comments[3], db.comments[4]]
247+
request(server)
248+
.get('/posts?_embed=comments')
249+
.expect('Content-Type', /json/)
250+
.expect(posts)
251+
.expect(200, done)
252+
})
253+
})
254+
255+
describe('GET /:resource?_embed&_embed=', function () {
256+
it('should respond with corresponding resources and embedded resources', function (done) {
257+
var posts = _.cloneDeep(db.posts)
258+
posts[0].comments = [db.comments[0], db.comments[1]]
259+
posts[0].refs = [db.refs[0]]
260+
posts[1].comments = [db.comments[2], db.comments[3], db.comments[4]]
261+
posts[1].refs = []
262+
request(server)
263+
.get('/posts?_embed=comments&_embed=refs')
264+
.expect('Content-Type', /json/)
265+
.expect(posts)
266+
.expect(200, done)
267+
})
268+
})
269+
241270
describe('GET /:resource/:id?_embed=', function () {
242-
it('should respond with corresponding resource and embedded other resource', function (done) {
271+
it('should respond with corresponding resources and embedded resources', function (done) {
243272
var posts = db.posts[0]
244273
posts.comments = [db.comments[0], db.comments[1]]
245274
request(server)
@@ -251,7 +280,7 @@ describe('Server', function () {
251280
})
252281

253282
describe('GET /:resource/:id?_embed=&_embed=', function () {
254-
it('should respond with corresponding resource and embedded other resources', function (done) {
283+
it('should respond with corresponding resource and embedded resources', function (done) {
255284
var posts = db.posts[0]
256285
posts.comments = [db.comments[0], db.comments[1]]
257286
posts.refs = [db.refs[0]]
@@ -263,6 +292,18 @@ describe('Server', function () {
263292
})
264293
})
265294

295+
describe('GET /:resource?_expand=', function () {
296+
it('should respond with corresponding resource and expanded inner resources', function (done) {
297+
var refs = _.cloneDeep(db.refs)
298+
refs[0].post = db.posts[0]
299+
request(server)
300+
.get('/refs?_expand=post')
301+
.expect('Content-Type', /json/)
302+
.expect(refs)
303+
.expect(200, done)
304+
})
305+
})
306+
266307
describe('GET /:resource/:id?_expand=', function () {
267308
it('should respond with corresponding resource and expanded inner resources', function (done) {
268309
var comments = db.comments[0]
@@ -275,6 +316,19 @@ describe('Server', function () {
275316
})
276317
})
277318

319+
describe('GET /:resource?_expand=&_expand', function () {
320+
it('should respond with corresponding resource and expanded inner resources', function (done) {
321+
var refs = _.cloneDeep(db.refs)
322+
refs[0].post = db.posts[0]
323+
refs[0].user = db.users[0]
324+
request(server)
325+
.get('/refs?_expand=post&_expand=user')
326+
.expect('Content-Type', /json/)
327+
.expect(refs)
328+
.expect(200, done)
329+
})
330+
})
331+
278332
describe('GET /:resource/:id?_expand=&_expand=', function () {
279333
it('should respond with corresponding resource and expanded inner resources', function (done) {
280334
var comments = db.comments[0]

0 commit comments

Comments
 (0)