mirror of
https://github.com/typicode/json-server.git
synced 2025-07-28 04:32:24 +08:00
Add singular resources
This commit is contained in:
84
src/server/router/index.js
Normal file
84
src/server/router/index.js
Normal 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
|
||||||
|
}
|
18
src/server/router/nested.js
Normal file
18
src/server/router/nested.js
Normal 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
|
||||||
|
}
|
@ -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
|
||||||
}
|
}
|
40
src/server/router/singular.js
Normal file
40
src/server/router/singular.js
Normal 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
67
test/server/singular.js
Normal 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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
Reference in New Issue
Block a user