-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
121 lines (106 loc) · 3.91 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
var LevelRest = require('level-rest-parser')
var RestParser = require('rest-parser')
var http = require('http')
var path = require('path')
var assert = require('assert')
module.exports = Nanoapp
function Nanoapp (api, opt) {
if (!(this instanceof Nanoapp)) return new Nanoapp(api, opt)
opt = opt || {}
assert.ok(api, 'Nanoapp: api must be defined')
assert.equal(typeof opt, 'object', 'Nanoapp: opt must be an object')
this.api = api
this.prefix = '/api/v' + (opt.version || '1')
opt.default
? this.api.route('default', opt.default)
: this.api.route('default', function (req, res, ctx) { ctx.send(404, {}) })
}
Nanoapp.prototype.model = function (db, schema) {
assert.ok(db, 'Nanoapp: db must be defined')
assert.equal(typeof schema, 'string', 'Nanoapp: schema must be a string')
var model = new RestParser(LevelRest(db, {
schema: require(path.join(process.cwd(), schema))
}))
return model
}
Nanoapp.prototype.resource = function (model, opt) {
assert.ok(typeof opt === 'object' || typeof opt === 'string', 'Nanoapp: opt must be an object or a string')
assert.ok(!opt.only || !opt.except, 'Nanoapp: can not define `only` and `except` options at the same time')
var route = '/' + (typeof opt === 'string' ? opt : opt.route)
assert.equal(typeof route, 'string', 'Nanoapp: route not defined')
var noIdMethods = ['GET', 'POST']
var idMethods = ['GET', 'PUT', 'DELETE']
if (opt.only) {
noIdMethods = noIdMethods.filter(function (method) {
return opt.only.indexOf(method) > -1
})
idMethods = idMethods.filter(function (method) {
return opt.only.indexOf(method) > -1
})
}
if (opt.except) {
noIdMethods = noIdMethods.filter(function (method) {
return opt.except.indexOf(method) < 0
})
idMethods = idMethods.filter(function (method) {
return opt.except.indexOf(method) < 0
})
}
noIdMethods.length > 0 && this.api.route(noIdMethods, this.prefix + route, dispatch(model, opt))
idMethods.length > 0 && this.api.route(idMethods, this.prefix + route + '/:id', dispatch(model, opt))
}
Nanoapp.prototype.route = function (method, route, handler) {
assert.equal(typeof method, 'string')
assert.equal(typeof route, 'string')
assert.equal(typeof handler, 'function')
this.api.route(method, route, handler)
}
Nanoapp.prototype.start = function (cb) {
cb = cb || function () {}
assert.equal(typeof cb, 'function', 'Nanoapp: cb must be a function')
var handler = this.api.start()
var server = http.createServer(handler)
server.listen(process.env.PORT || 8080, process.env.IP || 'localhost', cb)
return server
}
function dispatch (model, opt) {
return function (req, res, ctx) {
if (opt.before) {
assert.equal(typeof opt.before, 'function', 'Nanoapp: before hook must be a function')
opt.before(req, res, ctx, next)
} else {
next(req, res, ctx)
}
function next (req, res, ctx) {
if (opt.after) assert.equal(typeof opt.after, 'function', 'Nanoapp: after hook must be a function')
model.dispatch(req, Object.assign({ valueEncoding: 'json' }, ctx.params), function (err, data) {
if (err) {
if (err.notFound) {
ctx.send(404, { message: 'resource not found' })
} else {
ctx.send(500, { message: 'internal server error' })
}
} else {
if (!data) {
if (req.method !== 'DELETE') {
ctx.send(404, { message: 'resource not found' })
} else {
if (opt.after) {
opt.after(req, res, ctx)
} else {
ctx.send(200, { id: ctx.params.id }, { 'content-type': 'json' })
}
}
} else {
if (opt.after) {
ctx.data = data
opt.after(req, res, ctx)
} else {
ctx.send(200, JSON.stringify(data), { 'content-type': 'json' })
}
}
}
})
}
}
}