33/**
44 * Lightweight web framework for your serverless applications
55 * @author Jeremy Daly <[email protected] > 6- * @version 0.3 .0
6+ * @version 0.5 .0
77 * @license MIT
88 */
99
10- const REQUEST = require ( './request.js' ) // Response object
11- const RESPONSE = require ( './response.js' ) // Response object
12- const Promise = require ( 'bluebird' ) // Promise library
10+ const REQUEST = require ( './lib/request.js' ) // Response object
11+ const RESPONSE = require ( './lib/response.js' ) // Response object
1312
1413// Create the API class
1514class API {
@@ -51,47 +50,24 @@ class API {
5150 // Executed after the callback
5251 this . _finally = ( ) => { }
5352
54- // Promise placeholder for final route promise resolution
55- this . _promise = function ( ) { console . log ( 'no promise to resolve' ) }
56- this . _reject = function ( ) { console . log ( 'no promise to reject' ) }
57-
5853 // Global error status
5954 this . _errorStatus = 500
6055
61- // Testing flag
56+ // Testing flag (disables logging)
6257 this . _test = false
6358
6459 } // end constructor
6560
66- // GET: convenience method
67- get ( path , handler ) {
68- this . METHOD ( 'GET' , path , handler )
69- }
7061
71- // POST: convenience method
72- post ( path , handler ) {
73- this . METHOD ( 'POST' , path , handler )
74- }
7562
76- // PUT: convenience method
77- put ( path , handler ) {
78- this . METHOD ( 'PUT' , path , handler )
79- }
63+ // Convenience methods (path, handler)
64+ get ( p , h ) { this . METHOD ( 'GET' , p , h ) }
65+ post ( p , h ) { this . METHOD ( 'POST' , p , h ) }
66+ put ( p , h ) { this . METHOD ( 'PUT' , p , h ) }
67+ patch ( p , h ) { this . METHOD ( 'PATCH' , p , h ) }
68+ delete ( p , h ) { this . METHOD ( 'DELETE' , p , h ) }
69+ options ( p , h ) { this . METHOD ( 'OPTIONS' , p , h ) }
8070
81- // PATCH: convenience method
82- patch ( path , handler ) {
83- this . METHOD ( 'PATCH' , path , handler )
84- }
85-
86- // DELETE: convenience method
87- delete ( path , handler ) {
88- this . METHOD ( 'DELETE' , path , handler )
89- }
90-
91- // OPTIONS: convenience method
92- options ( path , handler ) {
93- this . METHOD ( 'OPTIONS' , path , handler )
94- }
9571
9672 // METHOD: Adds method and handler to routes
9773 METHOD ( method , path , handler ) {
@@ -124,112 +100,88 @@ class API {
124100 this . _routes ,
125101 ( i === route . length - 1 ? { [ '__' + method . toUpperCase ( ) ] : { vars : pathVars , handler : handler , route : '/' + parsedPath . join ( '/' ) } } : { } ) ,
126102 route . slice ( 0 , i + 1 )
127- ) ;
103+ )
128104
129105 } // end for loop
130106
131107 } // end main METHOD function
132108
133109
134- // RUN: This runs the routes
135- run ( event , context , cb ) { // TODO: Make this dynamic
136-
137- this . startTimer ( 'total' )
138110
139- this . _done = false
111+ // RUN: This runs the routes
112+ async run ( event , context , cb ) {
140113
141114 // Set the event, context and callback
142115 this . _event = event
143116 this . _context = context
144117 this . _cb = cb
145118
146- // Initalize response object
147- let response = new RESPONSE ( this )
148- let request = { }
119+ try {
120+ // Initalize response and request objects
121+ this . response = new RESPONSE ( this )
122+ this . request = new REQUEST ( this )
149123
150- Promise . try ( ( ) => { // Start a promise
124+ // Loop through the middleware and await response
125+ for ( const mw of this . _middleware ) {
126+ await new Promise ( r => { mw ( this . request , this . response , ( ) => { r ( ) } ) } )
127+ } // end for
151128
152- // Initalize the request object
153- request = new REQUEST ( this )
129+ // Execute the primary handler
130+ await this . handler ( this . request , this . response )
154131
155- // Execute the request
156- return this . execute ( request , response )
132+ } catch ( e ) {
133+ this . catchErrors ( e )
134+ }
157135
158- } ) . catch ( ( e ) => {
136+ } // end run function
159137
160- // Error messages should never be base64 encoded
161- response . _isBase64 = false
162138
163- // Strip the headers (TODO: find a better way to handle this)
164- response . _headers = { }
165139
166- let message ;
140+ // Catch all async/sync errors
141+ async catchErrors ( e ) {
167142
168- if ( e instanceof Error ) {
169- response . status ( this . _errorStatus )
170- message = e . message
171- ! this . _test && console . log ( e )
172- } else {
173- message = e
174- ! this . _test && console . log ( 'API Error:' , e )
175- }
143+ // Error messages should never be base64 encoded
144+ this . response . _isBase64 = false
176145
177- // Execute error middleware
178- if ( this . _errors . length > 0 ) {
179-
180- // Init stack queue
181- let queue = [ ]
182-
183- // Loop through the middleware and queue promises
184- for ( let i in this . _errors ) {
185- queue . push ( ( ) => {
186- return new Promise ( ( resolve , reject ) => {
187- this . _promise = ( ) => { resolve ( ) } // keep track of the last resolve()
188- this . _reject = ( e ) => { reject ( e ) } // keep track of the last reject()
189- this . _errors [ i ] ( e , request , response , ( ) => { resolve ( ) } ) // execute the errors with the resolve callback
190- } ) // end promise
191- } ) // end queue
192- } // end for
193-
194- // Return Promise.each serialially
195- return Promise . each ( queue , function ( queue_item ) {
196- return queue_item ( )
197- } ) . then ( ( ) => {
198- response . json ( { 'error' :message } )
199- } )
146+ // Strip the headers (TODO: find a better way to handle this)
147+ this . response . _headers = { }
200148
201- } else {
202- response . json ( { 'error' :message } )
203- }
149+ let message ;
204150
205- } ) . finally ( ( ) => {
206- this . _finally ( request , response )
207- } )
208- } // end run function
151+ if ( e instanceof Error ) {
152+ this . response . status ( this . _errorStatus )
153+ message = e . message
154+ ! this . _test && console . log ( e )
155+ } else {
156+ message = e
157+ ! this . _test && console . log ( 'API Error:' , e )
158+ }
209159
160+ // Execute error middleware
161+ for ( const err of this . _errors ) {
162+ // Promisify error middleware
163+ await new Promise ( r => { err ( e , this . request , this . response , ( ) => { r ( ) } ) } )
164+ } // end for
210165
211- // Custom callback
212- _callback ( err , res ) {
166+ this . response . json ( { 'error' :message } )
213167
214- // Resolve any outstanding promise
215- this . _promise ( )
168+ } // end catch
216169
217- this . _done = true
218170
219- this . endTimer ( 'total' )
220171
221- if ( res ) {
222- if ( this . _debug ) {
223- console . log ( this . _procTimes )
224- }
225- }
172+ // Custom callback
173+ async _callback ( err , res ) {
174+
175+ // Execute finally
176+ await this . _finally ( this . request , this . response )
226177
227178 // Execute the primary callback
228179 this . _cb ( err , res )
229180
230181 } // end _callback
231182
232183
184+
233185 // Middleware handler
234186 use ( fn ) {
235187 if ( fn . length === 3 ) {
@@ -241,79 +193,12 @@ class API {
241193 }
242194 } // end use
243195
244- // Finally function
196+
197+ // Finally handler
245198 finally ( fn ) {
246199 this . _finally = fn
247200 }
248201
249- // Process
250- execute ( req , res ) {
251-
252- // Init stack queue
253- let queue = [ ]
254-
255- // If execute is called after the app is done, just return out
256- if ( this . _done ) { return ; }
257-
258- // If there is middleware
259- if ( this . _middleware . length > 0 ) {
260- // Loop through the middleware and queue promises
261- for ( let i in this . _middleware ) {
262- queue . push ( ( ) => {
263- return new Promise ( ( resolve , reject ) => {
264- this . _promise = ( ) => { resolve ( ) } // keep track of the last resolve()
265- this . _reject = ( e ) => { reject ( e ) } // keep track of the last reject()
266- this . _middleware [ i ] ( req , res , ( ) => { resolve ( ) } ) // execute the middleware with the resolve callback
267- } ) // end promise
268- } ) // end queue
269- } // end for
270- } // end if
271-
272- // Push the main execution path to the queue stack
273- queue . push ( ( ) => {
274- return new Promise ( ( resolve , reject ) => {
275- this . _promise = ( ) => { resolve ( ) } // keep track of the last resolve()
276- this . _reject = ( e ) => { reject ( e ) } // keep track of the last reject()
277- this . handler ( req , res ) // execute the handler with no callback
278- } )
279- } )
280-
281- // Return Promise.each serialially
282- return Promise . each ( queue , function ( queue_item ) {
283- return queue_item ( )
284- } )
285-
286- } // end execute
287-
288-
289-
290- //-------------------------------------------------------------------------//
291- // TIMER FUNCTIONS
292- //-------------------------------------------------------------------------//
293-
294- // Returns the calculated processing times from all stopped timers
295- getTimers ( timer ) {
296- if ( timer ) {
297- return this . _procTimes [ timer ]
298- } else {
299- return this . _procTimes
300- }
301- } // end getTimers
302-
303- // Starts a timer for debugging purposes
304- startTimer ( name ) {
305- this . _timers [ name ] = Date . now ( )
306- } // end startTimer
307-
308- // Ends a timer and calculates the total processing time
309- endTimer ( name ) {
310- try {
311- this . _procTimes [ name ] = ( Date . now ( ) - this . _timers [ name ] ) + ' ms'
312- delete this . _timers [ name ]
313- } catch ( e ) {
314- console . error ( 'Could not end timer: ' + name )
315- }
316- } // end endTimer
317202
318203
319204 //-------------------------------------------------------------------------//
@@ -324,20 +209,20 @@ class API {
324209 return path . trim ( ) . replace ( / ^ \/ ( .* ?) ( \/ ) * $ / , '$1' ) . split ( '/' ) . filter ( x => x . trim ( ) !== '' )
325210 }
326211
327-
212+ // Recursive function to create routes object
328213 setRoute ( obj , value , path ) {
329214 if ( typeof path === "string" ) {
330215 let path = path . split ( '.' )
331216 }
332217
333218 if ( path . length > 1 ) {
334219 let p = path . shift ( )
335- if ( obj [ p ] === null ) { // || typeof obj[p] !== 'object') {
220+ if ( obj [ p ] === null ) {
336221 obj [ p ] = { }
337222 }
338223 this . setRoute ( obj [ p ] , value , path )
339224 } else {
340- if ( obj [ path [ 0 ] ] === null ) { // || typeof obj[path[0]] !== 'object') {
225+ if ( obj [ path [ 0 ] ] === null ) {
341226 obj [ path [ 0 ] ] = value
342227 } else {
343228 obj [ path [ 0 ] ] = Object . assign ( value , obj [ path [ 0 ] ] )
@@ -386,7 +271,9 @@ class API {
386271
387272 } // end register
388273
274+
389275} // end API class
390276
391- // Export the API class
277+
278+ // Export the API class as a new instance
392279module . exports = opts => new API ( opts )
0 commit comments