From 5f495f0e02e8df47224b2afb3af511fa2e6f806e Mon Sep 17 00:00:00 2001 From: Filippo Conti Date: Sat, 9 Mar 2019 13:38:47 +0100 Subject: [PATCH 1/3] Fix: Cast id to int on plurals Threat the request param as integer closes #925, closes #396 --- __tests__/server/plural-with-custom-foreign-key.js | 2 +- __tests__/server/plural.js | 2 +- src/server/router/nested.js | 2 +- src/server/router/plural.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/__tests__/server/plural-with-custom-foreign-key.js b/__tests__/server/plural-with-custom-foreign-key.js index 0bee110ed..0bcd3ffe7 100644 --- a/__tests__/server/plural-with-custom-foreign-key.js +++ b/__tests__/server/plural-with-custom-foreign-key.js @@ -100,7 +100,7 @@ describe('Server with custom foreign key', () => { .post('/posts/1/comments') .send({ body: 'foo' }) .expect('Content-Type', /json/) - .expect({ id: 4, post_id: '1', body: 'foo' }) + .expect({ id: 4, post_id: 1, body: 'foo' }) .expect(201)) }) diff --git a/__tests__/server/plural.js b/__tests__/server/plural.js index 338d75a62..ef65d002e 100644 --- a/__tests__/server/plural.js +++ b/__tests__/server/plural.js @@ -554,7 +554,7 @@ describe('Server', () => { .post('/posts/1/comments') .send({ body: 'foo' }) .expect('Content-Type', /json/) - .expect({ id: 6, postId: '1', body: 'foo' }) + .expect({ id: 6, postId: 1, body: 'foo' }) .expect(201)) }) diff --git a/src/server/router/nested.js b/src/server/router/nested.js index 17defeaaf..8825d92b7 100644 --- a/src/server/router/nested.js +++ b/src/server/router/nested.js @@ -17,7 +17,7 @@ module.exports = opts => { // Rewrite URL (/:resource/:id/:nested -> /:nested) and request body function post(req, res, next) { const prop = pluralize.singular(req.params.resource) - req.body[`${prop}${opts.foreignKeySuffix}`] = req.params.id + req.body[`${prop}${opts.foreignKeySuffix}`] = parseInt(req.params.id) req.url = `/${req.params.nested}` next() } diff --git a/src/server/router/plural.js b/src/server/router/plural.js index 04354fb26..84e42aed5 100644 --- a/src/server/router/plural.js +++ b/src/server/router/plural.js @@ -281,7 +281,7 @@ module.exports = (db, name, opts) => { // PUT /name/:id // PATCH /name/:id function update(req, res, next) { - const id = req.params.id + const id = parseInt(req.params.id) let resource if (opts._isFake) { From 48810c6b04c39e342329dac71caa3ca9f0a623be Mon Sep 17 00:00:00 2001 From: Filippo Conti Date: Tue, 19 Mar 2019 08:27:31 +0100 Subject: [PATCH 2/3] Feat: Support for bulk insertion Added support for bulk insertion on plural routes and nested routes, closes #482 --- __tests__/server/plural.js | 59 +++++++++++++++++++++++++++++++++++++ src/server/router/nested.js | 13 ++++++-- src/server/router/plural.js | 48 +++++++++++++++++++++--------- 3 files changed, 104 insertions(+), 16 deletions(-) diff --git a/__tests__/server/plural.js b/__tests__/server/plural.js index ef65d002e..fda7d583c 100644 --- a/__tests__/server/plural.js +++ b/__tests__/server/plural.js @@ -348,6 +348,13 @@ describe('Server', () => { .expect('Content-Type', /json/) .expect(db.comments.slice(1)) .expect(200)) + + test.skip('should accept multiple parameters', () => + request(server) + .get('/comments?id_ne=1&id_ne=2') + .expect('Content-Type', /json/) + .expect(db.comments.slice(1)) + .expect(200)) }) describe('GET /:resource?attr_like=', () => { @@ -526,6 +533,32 @@ describe('Server', () => { assert.strictEqual(db.posts.length, 3) }) + test('should support bulk insertion', async () => { + await request(server) + .post('/posts') + .send([ + { + body: 'foo bar' + }, + { + body: 'foo baz' + } + ]) + .expect('Content-Type', /json/) + .expect([ + { + id: 3, + body: 'foo bar' + }, + { + id: 4, + body: 'foo baz' + } + ]) + .expect(201) + assert.strictEqual(db.posts.length, 4) + }) + test('should support x-www-form-urlencoded', async () => { await request(server) .post('/posts') @@ -556,6 +589,32 @@ describe('Server', () => { .expect('Content-Type', /json/) .expect({ id: 6, postId: 1, body: 'foo' }) .expect(201)) + + test('should support bulk insertion', () => + request(server) + .post('/posts/1/comments') + .send([ + { + body: 'foo' + }, + { + body: 'bar' + } + ]) + .expect('Content-Type', /json/) + .expect([ + { + id: 6, + postId: 1, + body: 'foo' + }, + { + id: 7, + postId: 1, + body: 'bar' + } + ]) + .expect(201)) }) describe('POST /:resource?_delay=', () => { diff --git a/src/server/router/nested.js b/src/server/router/nested.js index 8825d92b7..6956f4d4c 100644 --- a/src/server/router/nested.js +++ b/src/server/router/nested.js @@ -1,3 +1,4 @@ +const _ = require('lodash') const express = require('express') const pluralize = require('pluralize') const delay = require('./delay') @@ -16,8 +17,16 @@ module.exports = opts => { // Rewrite URL (/:resource/:id/:nested -> /:nested) and request body function post(req, res, next) { - const prop = pluralize.singular(req.params.resource) - req.body[`${prop}${opts.foreignKeySuffix}`] = parseInt(req.params.id) + const id = parseInt(req.params.id) + const prop = pluralize.singular(req.params.resource) + opts.foreignKeySuffix + if (_.isArray(req.body)) { + req.body = req.body.map(r => ({ + ...r, + [prop]: id + })) + } else { + req.body[prop] = id + } req.url = `/${req.params.nested}` next() } diff --git a/src/server/router/plural.js b/src/server/router/plural.js index 84e42aed5..0f67e5b94 100644 --- a/src/server/router/plural.js +++ b/src/server/router/plural.js @@ -91,8 +91,8 @@ module.exports = (db, name, opts) => { delete req.query[query] }) + // Full-text search if (q) { - // Full-text search if (Array.isArray(q)) { q = q[0] } @@ -256,21 +256,41 @@ module.exports = (db, name, opts) => { // POST /name function create(req, res, next) { let resource - if (opts._isFake) { - const id = db - .get(name) - .createId() - .value() - resource = { ...req.body, id } + const body = req.body + + if (_.isArray(body)) { + resource = body.map(r => { + if (opts._isFake) { + return { + ...r, + id: db + .get(name) + .createId() + .value() + } + } + return db + .get(name) + .insert(r) + .value() + }) } else { - resource = db - .get(name) - .insert(req.body) - .value() - } + if (opts._isFake) { + const id = db + .get(name) + .createId() + .value() + resource = { ...body, id } + } else { + resource = db + .get(name) + .insert(body) + .value() + } - res.setHeader('Access-Control-Expose-Headers', 'Location') - res.location(`${getFullURL(req)}/${resource.id}`) + res.setHeader('Access-Control-Expose-Headers', 'Location') + res.location(`${getFullURL(req)}/${resource.id}`) + } res.status(201) res.locals.data = resource From 718db0dbe6eaba1a657092be28c5742168df357e Mon Sep 17 00:00:00 2001 From: Filippo Conti Date: Fri, 16 Aug 2019 23:39:42 +0200 Subject: [PATCH 3/3] Fix: Handle non numeric ids When nested route is called with a non numeric id it should not be parsed to int, otherwise numbers or numeric strings are parsed to int with base 10 --- __tests__/server/plural.js | 26 ++++++++++++++++++++++++++ src/server/router/nested.js | 3 ++- src/server/router/plural.js | 2 +- src/server/utils.js | 7 ++++++- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/__tests__/server/plural.js b/__tests__/server/plural.js index fda7d583c..16460fefc 100644 --- a/__tests__/server/plural.js +++ b/__tests__/server/plural.js @@ -615,6 +615,32 @@ describe('Server', () => { } ]) .expect(201)) + + test('should support bulk insertion with non numeric id', () => + request(server) + .post('/refs/abcd-1234/posts') + .send([ + { + body: 'foo' + }, + { + body: 'bar' + } + ]) + .expect('Content-Type', /json/) + .expect([ + { + id: 3, + refId: 'abcd-1234', + body: 'foo' + }, + { + id: 4, + refId: 'abcd-1234', + body: 'bar' + } + ]) + .expect(201)) }) describe('POST /:resource?_delay=', () => { diff --git a/src/server/router/nested.js b/src/server/router/nested.js index 6956f4d4c..919315524 100644 --- a/src/server/router/nested.js +++ b/src/server/router/nested.js @@ -2,6 +2,7 @@ const _ = require('lodash') const express = require('express') const pluralize = require('pluralize') const delay = require('./delay') +const utils = require('../utils') module.exports = opts => { const router = express.Router() @@ -17,7 +18,7 @@ module.exports = opts => { // Rewrite URL (/:resource/:id/:nested -> /:nested) and request body function post(req, res, next) { - const id = parseInt(req.params.id) + const id = utils.parseID(req.params.id) const prop = pluralize.singular(req.params.resource) + opts.foreignKeySuffix if (_.isArray(req.body)) { req.body = req.body.map(r => ({ diff --git a/src/server/router/plural.js b/src/server/router/plural.js index 0f67e5b94..b14253a60 100644 --- a/src/server/router/plural.js +++ b/src/server/router/plural.js @@ -301,7 +301,7 @@ module.exports = (db, name, opts) => { // PUT /name/:id // PATCH /name/:id function update(req, res, next) { - const id = parseInt(req.params.id) + const id = req.params.id let resource if (opts._isFake) { diff --git a/src/server/utils.js b/src/server/utils.js index 3339e7230..526d5f4c7 100644 --- a/src/server/utils.js +++ b/src/server/utils.js @@ -1,5 +1,10 @@ module.exports = { - getPage + getPage, + parseID +} + +function parseID(id) { + return /^\d+$/.test(id) ? +id : id } function getPage(array, page, perPage) {