Skip to content

Commit 394be89

Browse files
authored
Merge pull request #65 from jeremydaly/v0.8.1
v0.8.1
2 parents c773db4 + ecd257a commit 394be89

File tree

7 files changed

+80
-13
lines changed

7 files changed

+80
-13
lines changed

README.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Whatever you decide is best for your use case, **Lambda API** is there to suppor
6262
- [cookie()](#cookiename-value-options)
6363
- [cors()](#corsoptions)
6464
- [download()](#downloadfile--filename--options--callback)
65-
- [error()](#errormessage)
65+
- [error()](#errorcode-message-detail)
6666
- [etag()](#etagboolean)
6767
- [getHeader()](#getheaderkey)
6868
- [getLink()](#getlinks3path-expires-callback)
@@ -261,6 +261,36 @@ api.get('/users', (req,res) => {
261261

262262
**IMPORTANT:** You must either use a callback like `res.send()` **OR** `return` a value. Otherwise the execution will hang and no data will be sent to the user. Also, be sure not to return `undefined`, otherwise it will assume no response.
263263

264+
### A Note About Flow Control
265+
266+
While callbacks like `res.send()` and `res.error()` will trigger a response, they will not necessarily terminate execution of the current route function. Take a look at the following example:
267+
268+
```javascript
269+
api.get('/users', (req,res) => {
270+
271+
if (req.headers.test === 'test') {
272+
res.error('Throw an error')
273+
}
274+
275+
return { foo: 'bar' }
276+
})
277+
```
278+
279+
The example above would not have the intended result of displaying an error. `res.error()` would signal Lambda API to execute the error handling, but the function would continue to run. This would cause the function to `return` a response that would override the intended error. In this situation, you could either wrap the return in an `else` clause, or a cleaner approach would be to `return` the call to the `error()` method, like so:
280+
281+
```javascript
282+
api.get('/users', (req,res) => {
283+
284+
if (req.headers.test === 'test') {
285+
return res.error('Throw an error')
286+
}
287+
288+
return { foo: 'bar' }
289+
})
290+
```
291+
292+
`res.error()` does not have a return value (meaning it is `undefined`). However, the `return` tells the function to stop executing, and the call to `res.error()` handles and formats the appropriate response. This will allow Lambda API to properly return the expected results.
293+
264294
## Route Prefixing
265295

266296
Lambda API makes it easy to create multiple versions of the same api without changing routes by hand. The `register()` method allows you to load routes from an external file and prefix all of those routes using the `prefix` option. For example:
@@ -382,7 +412,7 @@ The `status` method allows you to set the status code that is returned to API Ga
382412

383413
```javascript
384414
api.get('/users', (req,res) => {
385-
res.status(401).error('Not Authorized')
415+
res.status(304).send('Not Modified')
386416
})
387417
```
388418

@@ -998,7 +1028,7 @@ api.use((req,res,next) => {
9981028
req.authorized = true
9991029
next() // continue execution
10001030
} else {
1001-
res.status(401).error('Not Authorized')
1031+
res.error(401,'Not Authorized')
10021032
}
10031033
})
10041034
```

index.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/**
44
* Lightweight web framework for your serverless applications
55
* @author Jeremy Daly <[email protected]>
6-
* @version 0.8.0
6+
* @version 0.8.1
77
* @license MIT
88
*/
99

@@ -184,10 +184,12 @@ class API {
184184
if (mw[0].length > 0 && !matched) continue
185185

186186
// Promisify middleware
187-
await new Promise(r => {
188-
let rtn = mw[1](request,response,() => { r() })
187+
await new Promise(async r => {
188+
let rtn = await mw[1](request,response,() => { r() })
189189
if (rtn) response.send(rtn)
190+
if (response._state === 'done') r() // if state is done, resolve promise
190191
})
192+
191193
} // end for
192194

193195
// Execute the primary handler if in processing state
@@ -239,7 +241,7 @@ class API {
239241
if (response._state === 'processing') {
240242

241243
// Flag error state (this will avoid infinite error loops)
242-
response._state === 'error'
244+
response._state = 'error'
243245

244246
// Execute error middleware
245247
for (const err of this._errors) {
@@ -372,7 +374,9 @@ class API {
372374

373375

374376
// Register routes with options
375-
register(fn,options) {
377+
register(fn,opts) {
378+
379+
let options = typeof opts === 'object' ? opts : {}
376380

377381
// Extract Prefix
378382
let prefix = options.prefix && options.prefix.toString().trim() !== '' ?

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "lambda-api",
3-
"version": "0.8.0",
3+
"version": "0.8.1",
44
"description": "Lightweight web framework for your serverless applications",
55
"main": "index.js",
66
"scripts": {

test/_testRoutes-v3.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict'
2+
3+
module.exports = function(app, opts) {
4+
5+
app.get('/test-register-no-options', function(req,res) {
6+
res.json({ path: req.path, route: req.route, method: req.method })
7+
})
8+
9+
} // end

test/middleware.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ api2.use('/test/testing',function(req,res,next) {
8686
next()
8787
})
8888

89+
api2.use('/test/error',function(req,res,next) {
90+
res.error(401,'Not Authorized')
91+
})
92+
8993

9094
api3.use(['/test','/test/:param1','/test2/*'],function(req,res,next) {
9195
req.testMiddlewareAll = true
@@ -166,6 +170,10 @@ api2.get('/test/:param1', function(req,res) {
166170
res.status(200).json({ method: 'get', middleware: req.testMiddleware ? true : false, middlewareWildcard: req.testMiddlewareWildcard ? true : false, middlewareParam: req.testMiddlewareParam ? true : false, middlewarePath: req.testMiddlewarePath ? true : false })
167171
})
168172

173+
api2.get('/test/error', function(req,res) {
174+
res.status(200).json({ message: 'should not get here' })
175+
})
176+
169177

170178
api3.get('/test', function(req,res) {
171179
res.status(200).json({ method: 'get', middleware: req.testMiddlewareAll ? true : false })
@@ -350,4 +358,13 @@ describe('Middleware Tests:', function() {
350358
}) // end it
351359

352360

361+
it('Trigger error in middleware', async function() {
362+
let _event = Object.assign({},event,{ path: '/test/error' })
363+
let result = await new Promise(r => api2.run(_event,{},(e,res) => { r(res) }))
364+
expect(result).to.deep.equal({
365+
headers: { 'content-type': 'application/json' },
366+
statusCode: 401, body: '{"error":"Not Authorized"}', isBase64Encoded: false })
367+
}) // end it
368+
369+
353370
}) // end MIDDLEWARE tests

test/register.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ const expect = require('chai').expect // Assertion library
44

55
// Init API instance
66
const api = require('../index')({ version: 'v1.0' })
7-
8-
// NOTE: Set test to true
9-
api._test = true;
7+
const api2 = require('../index')({ version: 'v2.0' })
108

119
let event = {
1210
httpMethod: 'get',
@@ -25,6 +23,9 @@ api.register(require('./_testRoutes-v1'), { prefix: '/v1' })
2523
api.register(require('./_testRoutes-v1'), { prefix: '/vX/vY' })
2624
api.register(require('./_testRoutes-v1'), { prefix: '' })
2725
api.register(require('./_testRoutes-v2'), { prefix: '/v2' })
26+
api.register(require('./_testRoutes-v3')) // no options
27+
api2.register(require('./_testRoutes-v3'), ['array']) // w/ array options
28+
api2.register(require('./_testRoutes-v3'), 'string') // w/ string
2829

2930
/******************************************************************************/
3031
/*** BEGIN TESTS ***/
@@ -129,4 +130,10 @@ describe('Register Tests:', function() {
129130
expect(result).to.deep.equal({ headers: { 'content-type': 'application/json' }, statusCode: 200, body: '{"path":"/v2/test-register/TEST/test","route":"/test-register/:param1/test","method":"GET","params":{"param1":"TEST"}}', isBase64Encoded: false })
130131
}) // end it
131132

133+
it('No options/no prefix', async function() {
134+
let _event = Object.assign({},event,{ path: '/test-register-no-options' })
135+
let result = await new Promise(r => api.run(_event,{},(e,res) => { r(res) }))
136+
expect(result).to.deep.equal({ headers: { 'content-type': 'application/json' }, statusCode: 200, body: '{"path":"/test-register-no-options","route":"/test-register-no-options","method":"GET"}', isBase64Encoded: false })
137+
}) // end it
138+
132139
}) // end ROUTE tests

test/sampling.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ describe('Sampling Tests:', function() {
366366
let deviation = Math.abs(((totalFixed+totalRate)/_log.length-1).toFixed(2))
367367

368368
// console.log(_log.length,totalFixed,totalRate,deviation)
369-
expect(deviation).to.be.below(0.12)
369+
expect(deviation).to.be.below(0.15)
370370
}) // end it
371371

372372

0 commit comments

Comments
 (0)