3
3
/**
4
4
* Lightweight web framework for your serverless applications
5
5
* @author Jeremy Daly <[email protected] >
6
- * @version 0.7 .0
6
+ * @version 0.8 .0
7
7
* @license MIT
8
8
*/
9
9
10
10
const REQUEST = require ( './lib/request.js' ) // Resquest object
11
11
const RESPONSE = require ( './lib/response.js' ) // Response object
12
12
const UTILS = require ( './lib/utils.js' ) // Require utils library
13
+ const LOGGER = require ( './lib/logger.js' ) // Require logger library
13
14
const prettyPrint = require ( './lib/prettyPrint' ) // Pretty print for debugging
14
15
15
16
// Create the API class
@@ -24,16 +25,36 @@ class API {
24
25
this . _callbackName = props && props . callback ? props . callback . trim ( ) : 'callback'
25
26
this . _mimeTypes = props && props . mimeTypes && typeof props . mimeTypes === 'object' ? props . mimeTypes : { }
26
27
28
+ // Set sampling info
29
+ this . _sampleCounts = { }
30
+
31
+ // Init request counter
32
+ this . _requestCount = 0
33
+
34
+ // Track init date/time
35
+ this . _initTime = Date . now ( )
36
+
37
+ // Logging levels
38
+ this . _logLevels = {
39
+ trace : 10 ,
40
+ debug : 20 ,
41
+ info : 30 ,
42
+ warn : 40 ,
43
+ error : 50 ,
44
+ fatal : 60
45
+ }
46
+
47
+ // Configure logger
48
+ this . _logger = LOGGER . config ( props && props . logger , this . _logLevels )
49
+
27
50
// Prefix stack w/ base
28
51
this . _prefix = this . parseRoute ( this . _base )
29
52
30
53
// Stores route mappings
31
54
this . _routes = { }
32
55
33
- // Default callback
34
- this . _cb = function ( ) {
35
- console . log ( 'No callback specified' ) // eslint-disable-line no-console
36
- }
56
+ // Init callback
57
+ this . _cb
37
58
38
59
// Middleware stack
39
60
this . _middleware = [ ]
@@ -47,12 +68,9 @@ class API {
47
68
// Executed after the callback
48
69
this . _finally = ( ) => { }
49
70
50
- // Global error status
71
+ // Global error status (used for response parsing errors)
51
72
this . _errorStatus = 500
52
73
53
- // Testing flag (disables logging)
54
- this . _test = false
55
-
56
74
} // end constructor
57
75
58
76
@@ -71,6 +89,10 @@ class API {
71
89
// METHOD: Adds method and handler to routes
72
90
METHOD ( method , path , handler ) {
73
91
92
+ if ( typeof handler !== 'function' ) {
93
+ throw new Error ( `No route handler specified for ${ method } method on ${ path } route.` )
94
+ }
95
+
74
96
// Ensure method is an array
75
97
let methods = Array . isArray ( method ) ? method : method . split ( ',' )
76
98
@@ -126,8 +148,8 @@ class API {
126
148
127
149
// Set the event, context and callback
128
150
this . _event = event
129
- this . _context = this . context = context
130
- this . _cb = cb
151
+ this . _context = this . context = typeof context === 'object' ? context : { }
152
+ this . _cb = cb ? cb : undefined
131
153
132
154
// Initalize request and response objects
133
155
let request = new REQUEST ( this )
@@ -136,7 +158,7 @@ class API {
136
158
try {
137
159
138
160
// Parse the request
139
- request . parseRequest ( )
161
+ await request . parseRequest ( )
140
162
141
163
// Loop through the middleware and await response
142
164
for ( const mw of this . _middleware ) {
@@ -175,15 +197,18 @@ class API {
175
197
}
176
198
177
199
} catch ( e ) {
178
- this . catchErrors ( e , response )
200
+ await this . catchErrors ( e , response )
179
201
}
180
202
203
+ // Return the final response
204
+ return response . _response
205
+
181
206
} // end run function
182
207
183
208
184
209
185
210
// Catch all async/sync errors
186
- async catchErrors ( e , response ) {
211
+ async catchErrors ( e , response , code , detail ) {
187
212
188
213
// Error messages should never be base64 encoded
189
214
response . _isBase64 = false
@@ -193,13 +218,21 @@ class API {
193
218
194
219
let message
195
220
221
+ let info = {
222
+ detail,
223
+ statusCode : response . _statusCode ,
224
+ coldStart : response . _request . coldStart ,
225
+ stack : this . _logger . stack && e . stack || undefined
226
+ }
227
+
196
228
if ( e instanceof Error ) {
197
- response . status ( this . _errorStatus )
229
+ response . status ( code ? code : this . _errorStatus )
198
230
message = e . message
199
- ! this . _test && console . log ( e ) // eslint-disable-line no-console
231
+ this . log . fatal ( message , info )
200
232
} else {
233
+ response . status ( code )
201
234
message = e
202
- ! this . _test && console . log ( 'API Error:' , e ) // eslint-disable-line no-console
235
+ this . log . error ( message , info )
203
236
}
204
237
205
238
// If first time through, process error middleware
@@ -227,34 +260,55 @@ class API {
227
260
228
261
229
262
// Custom callback
230
- async _callback ( err , res , response ) {
263
+ async _callback ( err , res , response ) {
231
264
232
265
// Set done status
233
266
response . _state = 'done'
234
267
235
268
// Execute finally
236
269
await this . _finally ( response . _request , response )
237
270
271
+ // Output logs
272
+ response . _request . _logs . forEach ( log => {
273
+ console . log ( JSON . stringify ( this . _logger . detail ? // eslint-disable-line no-console
274
+ this . _logger . format ( log , response . _request , response ) : log ) )
275
+ } )
276
+
277
+ // Generate access log
278
+ if ( ( this . _logger . access || response . _request . _logs . length > 0 ) && this . _logger . access !== 'never' ) {
279
+ let access = Object . assign (
280
+ this . _logger . log ( 'access' , undefined , response . _request , response . _request . context ) ,
281
+ { statusCode : res . statusCode , coldStart : response . _request . coldStart , count : response . _request . requestCount }
282
+ )
283
+ console . log ( JSON . stringify ( this . _logger . format ( access , response . _request , response ) ) ) // eslint-disable-line no-console
284
+ }
285
+
238
286
// Execute the primary callback
239
- this . _cb ( err , res )
287
+ typeof this . _cb === 'function' && this . _cb ( err , res )
240
288
241
289
} // end _callback
242
290
243
291
244
292
245
293
// Middleware handler
246
- use ( path , handler ) {
294
+ use ( path ) {
247
295
248
- let fn = typeof path === 'function' ? path : handler
296
+ // Extract routes
249
297
let routes = typeof path === 'string' ? Array . of ( path ) : ( Array . isArray ( path ) ? path : [ ] )
250
298
251
- if ( fn . length === 3 ) {
252
- this . _middleware . push ( [ routes , fn ] )
253
- } else if ( fn . length === 4 ) {
254
- this . _errors . push ( fn )
255
- } else {
256
- throw new Error ( 'Middleware must have 3 or 4 parameters' )
299
+ // Add func args as middleware
300
+ for ( let arg in arguments ) {
301
+ if ( typeof arguments [ arg ] === 'function' ) {
302
+ if ( arguments [ arg ] . length === 3 ) {
303
+ this . _middleware . push ( [ routes , arguments [ arg ] ] )
304
+ } else if ( arguments [ arg ] . length === 4 ) {
305
+ this . _errors . push ( arguments [ arg ] )
306
+ } else {
307
+ throw new Error ( 'Middleware must have 3 or 4 parameters' )
308
+ }
309
+ }
257
310
}
311
+
258
312
} // end use
259
313
260
314
@@ -276,7 +330,7 @@ class API {
276
330
// Recursive function to create routes object
277
331
setRoute ( obj , value , path ) {
278
332
if ( typeof path === 'string' ) {
279
- let path = path . split ( '.' )
333
+ path = path . split ( '.' )
280
334
}
281
335
282
336
if ( path . length > 1 ) {
0 commit comments