Skip to content

Commit

Permalink
Merge pull request #65 from jeremydaly/v0.8.1
Browse files Browse the repository at this point in the history
v0.8.1
  • Loading branch information
jeremydaly authored Oct 10, 2018
2 parents c773db4 + ecd257a commit 394be89
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 13 deletions.
36 changes: 33 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Whatever you decide is best for your use case, **Lambda API** is there to suppor
- [cookie()](#cookiename-value-options)
- [cors()](#corsoptions)
- [download()](#downloadfile--filename--options--callback)
- [error()](#errormessage)
- [error()](#errorcode-message-detail)
- [etag()](#etagboolean)
- [getHeader()](#getheaderkey)
- [getLink()](#getlinks3path-expires-callback)
Expand Down Expand Up @@ -261,6 +261,36 @@ api.get('/users', (req,res) => {

**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.

### A Note About Flow Control

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:

```javascript
api.get('/users', (req,res) => {

if (req.headers.test === 'test') {
res.error('Throw an error')
}

return { foo: 'bar' }
})
```

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:

```javascript
api.get('/users', (req,res) => {

if (req.headers.test === 'test') {
return res.error('Throw an error')
}

return { foo: 'bar' }
})
```

`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.

## Route Prefixing

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:
Expand Down Expand Up @@ -382,7 +412,7 @@ The `status` method allows you to set the status code that is returned to API Ga

```javascript
api.get('/users', (req,res) => {
res.status(401).error('Not Authorized')
res.status(304).send('Not Modified')
})
```

Expand Down Expand Up @@ -998,7 +1028,7 @@ api.use((req,res,next) => {
req.authorized = true
next() // continue execution
} else {
res.status(401).error('Not Authorized')
res.error(401,'Not Authorized')
}
})
```
Expand Down
14 changes: 9 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Lightweight web framework for your serverless applications
* @author Jeremy Daly <[email protected]>
* @version 0.8.0
* @version 0.8.1
* @license MIT
*/

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

// Promisify middleware
await new Promise(r => {
let rtn = mw[1](request,response,() => { r() })
await new Promise(async r => {
let rtn = await mw[1](request,response,() => { r() })
if (rtn) response.send(rtn)
if (response._state === 'done') r() // if state is done, resolve promise
})

} // end for

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

// Flag error state (this will avoid infinite error loops)
response._state === 'error'
response._state = 'error'

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


// Register routes with options
register(fn,options) {
register(fn,opts) {

let options = typeof opts === 'object' ? opts : {}

// Extract Prefix
let prefix = options.prefix && options.prefix.toString().trim() !== '' ?
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lambda-api",
"version": "0.8.0",
"version": "0.8.1",
"description": "Lightweight web framework for your serverless applications",
"main": "index.js",
"scripts": {
Expand Down
9 changes: 9 additions & 0 deletions test/_testRoutes-v3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

module.exports = function(app, opts) {

app.get('/test-register-no-options', function(req,res) {
res.json({ path: req.path, route: req.route, method: req.method })
})

} // end
17 changes: 17 additions & 0 deletions test/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ api2.use('/test/testing',function(req,res,next) {
next()
})

api2.use('/test/error',function(req,res,next) {
res.error(401,'Not Authorized')
})


api3.use(['/test','/test/:param1','/test2/*'],function(req,res,next) {
req.testMiddlewareAll = true
Expand Down Expand Up @@ -166,6 +170,10 @@ api2.get('/test/:param1', function(req,res) {
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 })
})

api2.get('/test/error', function(req,res) {
res.status(200).json({ message: 'should not get here' })
})


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


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


}) // end MIDDLEWARE tests
13 changes: 10 additions & 3 deletions test/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ const expect = require('chai').expect // Assertion library

// Init API instance
const api = require('../index')({ version: 'v1.0' })

// NOTE: Set test to true
api._test = true;
const api2 = require('../index')({ version: 'v2.0' })

let event = {
httpMethod: 'get',
Expand All @@ -25,6 +23,9 @@ api.register(require('./_testRoutes-v1'), { prefix: '/v1' })
api.register(require('./_testRoutes-v1'), { prefix: '/vX/vY' })
api.register(require('./_testRoutes-v1'), { prefix: '' })
api.register(require('./_testRoutes-v2'), { prefix: '/v2' })
api.register(require('./_testRoutes-v3')) // no options
api2.register(require('./_testRoutes-v3'), ['array']) // w/ array options
api2.register(require('./_testRoutes-v3'), 'string') // w/ string

/******************************************************************************/
/*** BEGIN TESTS ***/
Expand Down Expand Up @@ -129,4 +130,10 @@ describe('Register Tests:', function() {
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 })
}) // end it

it('No options/no prefix', async function() {
let _event = Object.assign({},event,{ path: '/test-register-no-options' })
let result = await new Promise(r => api.run(_event,{},(e,res) => { r(res) }))
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 })
}) // end it

}) // end ROUTE tests
2 changes: 1 addition & 1 deletion test/sampling.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ describe('Sampling Tests:', function() {
let deviation = Math.abs(((totalFixed+totalRate)/_log.length-1).toFixed(2))

// console.log(_log.length,totalFixed,totalRate,deviation)
expect(deviation).to.be.below(0.12)
expect(deviation).to.be.below(0.15)
}) // end it


Expand Down

0 comments on commit 394be89

Please sign in to comment.