Add singular resources

This commit is contained in:
Typicode
2015-07-22 07:20:56 +02:00
parent f277035c52
commit 95f334f095
6 changed files with 222 additions and 77 deletions

View File

@ -0,0 +1,84 @@
var express = require('express')
var methodOverride = require('method-override')
var bodyParser = require('body-parser')
var _ = require('lodash')
var _db = require('underscore-db')
var low = require('lowdb')
var plural = require('./plural')
var nested = require('./nested')
var singular = require('./singular')
var mixins = require('../mixins')
module.exports = function (source) {
// Create router
var router = express.Router()
// Add middlewares
router.use(bodyParser.json({limit: '10mb'}))
router.use(bodyParser.urlencoded({extended: false}))
router.use(methodOverride())
// Create database
var db
if (_.isObject(source)) {
db = low()
db.object = source
} else {
db = low(source)
}
// Add underscore-db methods to db
db._.mixin(_db)
// Add specific mixins
db._.mixin(mixins)
// Expose database
router.db = db
// Expose database
router.db = db
// Expose render
router.render = function (req, res) {
res.jsonp(res.locals.data)
}
// GET /db
function showDatabase (req, res, next) {
res.locals.data = db.object
next()
}
router.get('/db', showDatabase)
router.use(nested())
// Create routes
for (var prop in db.object) {
if (_.isPlainObject(db.object[prop])) {
router.use('/' + prop, singular(db, prop))
continue
}
if (_.isArray(db.object[prop])) {
router.use('/' + prop, plural(db, prop))
continue
}
throw new Error('Unsupported type')
}
router.use(function (req, res) {
if (!res.locals.data) {
res.status(404)
res.locals.data = {}
}
router.render(req, res)
})
return router
}

View File

@ -0,0 +1,18 @@
var express = require('express')
var pluralize = require('pluralize')
var utils = require('../utils')
module.exports = function () {
var router = express.Router()
// Rewrite url to /:nested?:resourceId=:id
router.get('/:resource/:id/:nested', function (req, res, next) {
var prop = pluralize.singular(req.params.resource)
req.query[prop + 'Id'] = utils.toNative(req.params.id)
req.url = '/' + req.params.nested
next()
})
return router
}

View File

@ -1,69 +1,25 @@
var express = require('express') var express = require('express')
var methodOverride = require('method-override')
var bodyParser = require('body-parser')
var _ = require('lodash') var _ = require('lodash')
var _db = require('underscore-db')
var low = require('lowdb')
var pluralize = require('pluralize') var pluralize = require('pluralize')
var utils = require('./utils') var utils = require('../utils')
var mixins = require('./mixins')
module.exports = function (db, name) {
module.exports = function (source) {
// Create router // Create router
var router = express.Router() var router = express.Router()
// Add middlewares
router.use(bodyParser.json({limit: '10mb'}))
router.use(bodyParser.urlencoded({extended: false}))
router.use(methodOverride())
// Create database
var db
if (_.isObject(source)) {
db = low()
db.object = source
} else {
db = low(source)
}
// Add underscore-db methods to db
db._.mixin(_db)
// Add specific mixins
db._.mixin(mixins)
// Expose database
router.db = db
// Expose render
router.render = function (req, res) {
res.jsonp(res.locals.data)
}
// GET /db
function showDatabase (req, res, next) {
res.locals.data = db.object
next()
}
// GET /:resource // GET /:resource
// GET /:resource?q= // GET /:resource?q=
// GET /:resource?attr=&attr= // GET /:resource?attr=&attr=
// GET /:parent/:parentId/:resource?attr=&attr= // GET /:resource?_end=&*
// GET /*?*&_end= // GET /:resource?_start=&_end=&*
// GET /*?*&_start=&_end=
function list (req, res, next) { function list (req, res, next) {
// Test if resource exists
if (!db.object.hasOwnProperty(req.params.resource)) {
res.status(404)
return next()
}
// Filters list // Filters list
var filters = {} var filters = {}
// Resource chain // Resource chain
var chain = db(req.params.resource).chain() var chain = db(name).chain()
// Remove q, _start, _end, ... from req.query to avoid filtering using those // Remove q, _start, _end, ... from req.query to avoid filtering using those
// parameters // parameters
@ -96,12 +52,6 @@ module.exports = function (source) {
} }
// Add :parentId filter in case URL is like /:parent/:parentId/:resource
if (req.params.parent) {
var parent = pluralize.singular(req.params.parent)
filters[parent + 'Id'] = +req.params.parentId
}
// Add query parameters filters // Add query parameters filters
// Convert query parameters to their native counterparts // Convert query parameters to their native counterparts
for (var key in req.query) { for (var key in req.query) {
@ -157,7 +107,7 @@ module.exports = function (source) {
function show (req, res, next) { function show (req, res, next) {
var _embed = req.query._embed var _embed = req.query._embed
var id = utils.toNative(req.params.id) var id = utils.toNative(req.params.id)
var resource = db(req.params.resource) var resource = db(name)
.getById(id) .getById(id)
if (resource) { if (resource) {
@ -173,7 +123,7 @@ module.exports = function (source) {
&& otherResource.trim().length > 0 && otherResource.trim().length > 0
&& db.object[otherResource]) { && db.object[otherResource]) {
var query = {} var query = {}
var prop = pluralize.singular(req.params.resource) + 'Id' var prop = pluralize.singular(name) + 'Id'
query[prop] = id query[prop] = id
resource[otherResource] = db(otherResource).where(query) resource[otherResource] = db(otherResource).where(query)
@ -181,9 +131,6 @@ module.exports = function (source) {
}) })
res.locals.data = resource res.locals.data = resource
} else {
res.status(404)
res.locals.data = {}
} }
next() next()
@ -195,7 +142,7 @@ module.exports = function (source) {
req.body[key] = utils.toNative(req.body[key]) req.body[key] = utils.toNative(req.body[key])
} }
var resource = db(req.params.resource) var resource = db(name)
.insert(req.body) .insert(req.body)
res.status(201) res.status(201)
@ -210,14 +157,11 @@ module.exports = function (source) {
req.body[key] = utils.toNative(req.body[key]) req.body[key] = utils.toNative(req.body[key])
} }
var resource = db(req.params.resource) var resource = db(name)
.updateById(utils.toNative(req.params.id), req.body) .updateById(utils.toNative(req.params.id), req.body)
if (resource) { if (resource) {
res.locals.data = resource res.locals.data = resource
} else {
res.status(404)
res.locals.data = {}
} }
next() next()
@ -225,7 +169,7 @@ module.exports = function (source) {
// DELETE /:resource/:id // DELETE /:resource/:id
function destroy (req, res, next) { function destroy (req, res, next) {
db(req.params.resource).removeById(utils.toNative(req.params.id)) db(name).removeById(utils.toNative(req.params.id))
// Remove dependents documents // Remove dependents documents
var removable = db._.getRemovable(db.object) var removable = db._.getRemovable(db.object)
@ -238,23 +182,15 @@ module.exports = function (source) {
next() next()
} }
router.get('/db', showDatabase, router.render) router.route('/')
router.route('/:resource')
.get(list) .get(list)
.post(create) .post(create)
router.route('/:resource/:id') router.route('/:id')
.get(show) .get(show)
.put(update) .put(update)
.patch(update) .patch(update)
.delete(destroy) .delete(destroy)
router.get('/:parent/:parentId/:resource', list)
router.all('*', function (req, res) {
router.render(req, res)
})
return router return router
} }

View File

@ -0,0 +1,40 @@
var express = require('express')
var utils = require('../utils')
module.exports = function (db, name) {
var router = express.Router()
function show (req, res, next) {
res.locals.data = db.object[name]
next()
}
function create (req, res, next) {
for (var prop in req.body) {
req.body[prop] = utils.toNative(req.body[prop])
}
res.locals.data = db.object[name] = req.body
res.status(201)
next()
}
function update (req, res, next) {
for (var prop in req.body) {
db.object[name][prop] = utils.toNative(req.body[prop])
}
res.locals.data = db.object[name]
next()
}
router.route('/')
.get(show)
.post(create)
.put(update)
.patch(update)
return router
}

67
test/server/singular.js Normal file
View File

@ -0,0 +1,67 @@
var request = require('supertest')
var assert = require('assert')
var jsonServer = require('../../src/server')
/* global beforeEach, describe, it */
describe('Server', function () {
var server
var router
var db
beforeEach(function () {
db = {}
db.user = {
name: 'foo',
email: 'foo@example.com'
}
server = jsonServer.create()
router = jsonServer.router(db)
server.use(router)
})
describe('GET /:resource', function () {
it('should respond with corresponding resource', function (done) {
request(server)
.get('/user')
.expect(db.user)
.expect(200, done)
})
})
describe('POST /:resource', function () {
it('should create resource', function (done) {
var user = { name: 'bar' }
request(server)
.post('/user')
.send(user)
.expect(user)
.expect(201, done)
})
})
describe('PUT /:resource', function () {
it('should uptade resource', function (done) {
var user = { name: 'bar' }
request(server)
.put('/user')
.send(user)
.expect(db.user)
.expect(200, done)
})
})
describe('PATCH /:resource', function () {
it('should uptade resource', function (done) {
request(server)
.patch('/user')
.send({ name: 'bar' })
.expect({ name: 'bar', email: 'foo@example.com' })
.expect(200, done)
})
})
})