-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
146 lines (124 loc) · 4.33 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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
var http = require('http')
, _ = require('underscore')
// Local libs
, utils = require('./utils')
;
var
error = utils.scopedError('easyPI')
, log = utils.scopedLog('easyPI')
, slice = Array.prototype.slice
;
// API middleware for easiness
var easyPI = function (app, options) {
this.app = app;
this.response = {}
this.models = options.models;
this.options = _.extend({}, this.defaultOptions, options)
this._modelResource = new ModelResource(this, this.options.models)
// Initializes the routes caching array
this.routes = {};
this.orderedRoutes = [];
easyPI.methods.forEach(function (method) {
this.routes[method] = {};
}, this)
}
easyPI.prototype = {
// Options to get merged with the instance options
defaultOptions:{
// This prefix will be applied to all routes
routePrefix:''
},
// Configures a resourceful model in the API
model:function (options) {
this._modelResource.register(options);
},
// Wraps a route handler (get, post, etc..) and binds to this epi object
wrapRoute:function (obj) {
if (!obj) error('Invalid route configuration', obj);
var self = this;
// An array - let's wrap each of them
if (obj instanceof Array) {
return obj.map(function (handler) {
return self.wrapRoute(handler)
})
}
// Sanitizing
// Regular handler, converting for unique point of wrapping below
if (typeof obj == 'function') {
obj = {
handler:obj
}
}
// Middleware from our stack
else if (typeof obj == 'string') {
if (!this.middlewares[obj]) error('Invalid middleware', obj);
obj = {
handler:this.middlewares[obj]
}
}
// Here we are expecting a configurable handler, with rules of validation
if (typeof obj.handler != 'function') {
error('Invalid route handler', obj.handler, obj);
}
return function (req, res, next) {
var epi = res.epi || (res.epi = new Response(self, req, res, next));
try {
// Default route validation rules
if (obj.rules) {
epi.rules(obj.rules);
}
if (obj.queryRules) {
epi.errors.query.rules(obj.queryRules);
}
if (obj.paramsRules) {
epi.errors.params.rules(obj.paramsRules);
}
if (!epi.validate()) return;
obj.handler.call(this, req, epi, next)
} catch (e) {
epi.raise(e)
}
}
},
// Gets a descriptor for the given route
routeDescriptor:function (method, route) {
return method.toUpperCase() + ' ' + (this.options.routePrefix + route)
},
// Prints all the registered routes to the console
printRoutes:function () {
console.log('-------------------------')
console.log("Registered routes:")
console.log('-------------------------')
this.orderedRoutes.forEach(function (route) {
console.log(route.split(' ').join("\t"))
})
console.log('-------------------------')
}
};
// Methods accepted for routing
easyPI.methods = ['get', 'post', 'delete', 'put']
// HTTP Verbs for routing
easyPI.methods.forEach(function (method) {
easyPI.prototype[method] = function (route) {
var self = this;
// Route Uniqueness
if (this.routes[method][route]) {
error('Route already defined ', this.routeDescriptor(method, route));
}
this.routes[method][route] = true;
this.orderedRoutes.push(this.routeDescriptor(method, route))
// Handler
this.app[method].apply(this.app,
[this.options.routePrefix + route]
// All the middlewares will now be wrapped by the EPI object
.concat(slice.call(arguments, 1).map(function (cb) {
return self.wrapRoute(cb)
}
))
)
}
})
easyPI.prototype.middlewares = require('./middlewares');
var Response = easyPI.Response = require('./response')
var ModelResource = easyPI.ModelResource = require('./modelResource');
module.exports = easyPI;