From bbc2011ec3e5b9ba9f30e96aa928558ee11814ae Mon Sep 17 00:00:00 2001 From: typicode Date: Tue, 25 Dec 2018 23:29:08 +0100 Subject: [PATCH] Add option to plural routes --- __tests__/server/plural-fake.js | 81 +++++++++++++++++++++++++++++++++ src/server/router/index.js | 2 +- src/server/router/plural.js | 70 ++++++++++++++++++++-------- 3 files changed, 132 insertions(+), 21 deletions(-) create mode 100644 __tests__/server/plural-fake.js diff --git a/__tests__/server/plural-fake.js b/__tests__/server/plural-fake.js new file mode 100644 index 0000000..eb55c6a --- /dev/null +++ b/__tests__/server/plural-fake.js @@ -0,0 +1,81 @@ +const assert = require('assert') +const request = require('supertest') +const jsonServer = require('../../src/server') + +describe('Fake server', () => { + let server + let router + let db + + beforeEach(() => { + db = {} + + db.posts = [{ id: 1, body: 'foo' }, { id: 2, body: 'bar' }] + + server = jsonServer.create() + router = jsonServer.router(db, { _isFake: true }) + server.use(jsonServer.defaults()) + server.use(router) + }) + + describe('POST /:resource', () => { + test('should respond with json, create a resource and increment id', async () => { + await request(server) + .post('/posts') + .send({ body: 'foo', booleanValue: true, integerValue: 1 }) + .expect('Access-Control-Expose-Headers', 'Location') + .expect('Location', /posts\/3$/) + .expect('Content-Type', /json/) + .expect({ id: 3, body: 'foo', booleanValue: true, integerValue: 1 }) + .expect(201) + // assert it was not created in database + assert.equal(db.posts.length, 2) + }) + }) + + describe('PUT /:resource/:id', () => { + test('should respond with json and replace resource', async () => { + const post = { id: 1, booleanValue: true, integerValue: 1 } + const res = await 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/) + .expect(post) + .expect(200) + // TODO find a "supertest" way to test this + // https://github.com/typicode/json-server/issues/396 + assert.deepStrictEqual(res.body, post) + // assert it was not created in database + assert.notDeepStrictEqual(db.posts[0], post) + }) + }) + + describe('PATCH /:resource/:id', () => { + test('should respond with json and update resource', async () => { + const partial = { body: 'bar' } + const post = { id: 1, body: 'bar' } + const res = await request(server) + .patch('/posts/1') + .send(partial) + .expect('Content-Type', /json/) + .expect(post) + .expect(200) + assert.deepStrictEqual(res.body, post) + // assert it was not created in database + assert.notDeepStrictEqual(db.posts[0], post) + }) + }) + + describe('DELETE /:resource/:id', () => { + test('should respond with empty data, destroy resource and dependent resources', async () => { + await request(server) + .del('/posts/1') + .expect({}) + .expect(200) + // assert it was not created in database + assert.equal(db.posts.length, 2) + }) + }) +}) diff --git a/src/server/router/index.js b/src/server/router/index.js index 7bac7bb..af2302e 100644 --- a/src/server/router/index.js +++ b/src/server/router/index.js @@ -12,7 +12,7 @@ const nested = require('./nested') const singular = require('./singular') const mixins = require('../mixins') -module.exports = (db, opts = { foreignKeySuffix: 'Id' }) => { +module.exports = (db, opts = { foreignKeySuffix: 'Id', _isFake: false }) => { if (typeof db === 'string') { db = low(new FileSync(db)) } else if (!_.has(db, '__chain__') || !_.has(db, '__wrapped__')) { diff --git a/src/server/router/plural.js b/src/server/router/plural.js index d2a90b7..04354fb 100644 --- a/src/server/router/plural.js +++ b/src/server/router/plural.js @@ -255,10 +255,19 @@ module.exports = (db, name, opts) => { // POST /name function create(req, res, next) { - const resource = db - .get(name) - .insert(req.body) - .value() + let resource + if (opts._isFake) { + const id = db + .get(name) + .createId() + .value() + resource = { ...req.body, id } + } else { + resource = db + .get(name) + .insert(req.body) + .value() + } res.setHeader('Access-Control-Expose-Headers', 'Location') res.location(`${getFullURL(req)}/${resource.id}`) @@ -273,14 +282,29 @@ module.exports = (db, name, opts) => { // PATCH /name/:id function update(req, res, next) { const id = req.params.id - let chain = db.get(name) + let resource - chain = - req.method === 'PATCH' - ? chain.updateById(id, req.body) - : chain.replaceById(id, req.body) + if (opts._isFake) { + resource = db + .get(name) + .getById(id) + .value() - const resource = chain.value() + if (req.method === 'PATCH') { + resource = { ...resource, ...req.body } + } else { + resource = { ...req.body, id: resource.id } + } + } else { + let chain = db.get(name) + + chain = + req.method === 'PATCH' + ? chain.updateById(id, req.body) + : chain.replaceById(id, req.body) + + resource = chain.value() + } if (resource) { res.locals.data = resource @@ -291,18 +315,24 @@ module.exports = (db, name, opts) => { // DELETE /name/:id function destroy(req, res, next) { - const resource = db - .get(name) - .removeById(req.params.id) - .value() + let resource - // Remove dependents documents - const removable = db._.getRemovable(db.getState(), opts) - removable.forEach(item => { - db.get(item.name) - .removeById(item.id) + if (opts._isFake) { + resource = db.get(name).value() + } else { + resource = db + .get(name) + .removeById(req.params.id) .value() - }) + + // Remove dependents documents + const removable = db._.getRemovable(db.getState(), opts) + removable.forEach(item => { + db.get(item.name) + .removeById(item.id) + .value() + }) + } if (resource) { res.locals.data = {}