Skip to content

Commit 7579ee3

Browse files
authored
Merge pull request #7 from jeremydaly/v0.1.0
v0.1.0
2 parents dd086c1 + 702cebc commit 7579ee3

File tree

5 files changed

+113
-29
lines changed

5 files changed

+113
-29
lines changed

README.md

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
11
# lambda-api
2-
**PLEASE NOTE:** This project is still in beta and should be used with caution in production.
32

43
[![Build Status](https://travis-ci.org/jeremydaly/lambda-api.svg?branch=master)](https://travis-ci.org/jeremydaly/lambda-api)
54
[![npm](https://img.shields.io/npm/v/lambda-api.svg)](https://www.npmjs.com/package/lambda-api)
65
[![npm](https://img.shields.io/npm/l/lambda-api.svg)](https://www.npmjs.com/package/lambda-api)
76

87
### Lightweight Node.js API for AWS Lambda
98

10-
Lambda API is a lightweight Node.js API router for use with AWS API Gateway and AWS Lambda using Lambda Proxy integration. This closely mirrors (and is based on Express.js) but is significantly stripped down to maximize performance with Lambda's stateless, single run executions. The API uses Bluebird promises to serialize asynchronous execution.
9+
Lambda API is a lightweight Node.js API router for use with AWS API Gateway and AWS Lambda using Lambda Proxy integration. This closely mirrors (and is based on) other routers like Express.js but is significantly stripped down to maximize performance with Lambda's stateless, single run executions. The API uses Bluebird promises to serialize asynchronous execution.
10+
11+
## Simple Example
12+
13+
```javascript
14+
const API = require('lambda-api') // API library
15+
16+
// Init API instance
17+
const api = new API({ version: 'v1.0', base: 'v1' });
18+
19+
api.get('/test', function(req,res) {
20+
res.status(200).json({ status: 'ok' })
21+
})
22+
23+
module.exports.handler = (event, context, callback) => {
24+
25+
// Run the request
26+
api.run(event,context,callback);
27+
28+
} // end handler
29+
```
1130

1231
## Lambda Proxy integration
1332
Lambda Proxy Integration is an option in API Gateway that allows the details of an API request to be passed as the `event` parameter of a Lambda function. A typical API Gateway request event with Lambda Proxy Integration enabled looks like this:
@@ -73,26 +92,6 @@ Lambda Proxy Integration is an option in API Gateway that allows the details of
7392

7493
The API automatically parses this information to create a normalized `REQUEST` object. The request can then be routed using the APIs methods.
7594

76-
## Simple Example
77-
78-
```javascript
79-
const API = require('lambda-api') // API library
80-
81-
// Init API instance
82-
const api = new API({ version: 'v1.0', base: 'v1' });
83-
84-
api.get('/test', function(req,res) {
85-
res.status(200).json({ status: 'ok' })
86-
})
87-
88-
module.exports.handler = (event, context, callback) => {
89-
90-
// Run the request
91-
api.run(event,context,callback);
92-
93-
} // end handler
94-
```
95-
9695
## Configuration
9796

9897
Include the `lambda-api` module into your Lambda handler script and initialize an instance. You can initialize the API with an optional `version` which can be accessed via the `REQUEST` object and a `base` path. The base path can be used to route multiple versions to different instances.
@@ -144,6 +143,7 @@ The `REQUEST` object contains a parsed and normalized request from API Gateway.
144143
- If the `Content-Type` header is `application/x-www-form-urlencoded`, it will attempt to parse a URL encoded string using `querystring`
145144
- Otherwise it will be plain text.
146145
- `route`: The matched route of the request
146+
- `requestContext`: The `requestContext` passed from the API Gateway
147147

148148
The request object can be used to pass additional information through the processing chain. For example, if you are using a piece of authentication middleware, you can add additional keys to the `REQUEST` object with information about the user. See [middleware](#middleware) for more information.
149149

@@ -248,6 +248,17 @@ api.use(function(req,res,next) {
248248

249249
The `next()` callback tells the system to continue executing. If this is not called then the system will hang and eventually timeout unless another request ending call such as `error` is called. You can define as many middleware functions as you want. They will execute serially and synchronously in the order in which they are defined.
250250

251+
### Clean Up
252+
The API has a built-in clean up method called 'finally()' that will execute after all middleware and routes have been completed, but before execution is complete. This can be used to close database connections or to perform other clean up functions. A clean up function can be defined using the `finally` method and requires a function with two parameters for the REQUEST and the RESPONSE as its only argument. For example:
253+
254+
```javascript
255+
api.finally(function(req,res) {
256+
// close unneeded database connections and perform clean up
257+
})
258+
```
259+
260+
The `RESPONSE` **CANNOT** be manipulated since it has already been generated. Only one `finally()` method can be defined. This uses the Bluebird `finally()` method internally and will execute after properly handled errors as well.
261+
251262
## Error Handling
252263
The API has simple built-in error handling that will log the error using `console.log`. These will be available via CloudWatch Logs. By default, errors will trigger a JSON response with the error message. If you would like to define additional error handling, you can define them using the `use` method similar to middleware. Error handling middleware must be defined as a function with **four** arguments instead of three like normal middleware. An additional `error` parameter must be added as the first parameter. This will contain the error object generated.
253264

index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
'use strict';
22

3+
/**
4+
* Lightweight Node.js API for AWS Lambda
5+
* @author Jeremy Daly <jeremy@jeremydaly>
6+
* @version 0.1.0
7+
* @license MIT
8+
*/
9+
310
const REQUEST = require('./request.js') // Response object
411
const RESPONSE = require('./response.js') // Response object
512
const Promise = require('bluebird') // Promise library

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.1.0-beta",
3+
"version": "0.1.0",
44
"description": "Lightweight Node.js API for AWS Lambda",
55
"main": "index.js",
66
"scripts": {

request.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,9 @@ class REQUEST {
2424

2525
// Set the headers
2626
this.headers = app._event.headers
27-
28-
// Set the requestContext from the event where one can find the authorizer Context from AWS
29-
this.requestContext = app._event.requestContext
3027

31-
// console.log(this.headers);
32-
// console.log(app._event.body);
33-
// console.log('Content-Type', this.headers['Content-Type']);
28+
// Set the requestContext
29+
this.requestContext = app._event.requestContext
3430

3531
// Set the body
3632
if (this.headers['Content-Type'] && this.headers['Content-Type'].includes("application/x-www-form-urlencoded")) {

test/finally.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
'use strict';
2+
3+
const Promise = require('bluebird') // Promise library
4+
const expect = require('chai').expect // Assertion library
5+
const API = require('../index') // API library
6+
7+
// Init API instance
8+
const api = new API({ version: 'v1.0', base: 'v1' });
9+
10+
// Simulate database module
11+
const fakeDatabase = { connected: true }
12+
13+
// NOTE: Set test to true
14+
api._test = true;
15+
16+
let event = {
17+
httpMethod: 'get',
18+
path: '/test',
19+
body: {},
20+
headers: {
21+
'Content-Type': 'application/json'
22+
}
23+
}
24+
25+
/******************************************************************************/
26+
/*** DEFINE TEST ROUTE ***/
27+
/******************************************************************************/
28+
api.get('/test', function(req,res) {
29+
res.status(200).json({
30+
method: 'get',
31+
status: 'ok',
32+
connected: fakeDatabase.connected
33+
})
34+
})
35+
36+
/******************************************************************************/
37+
/*** DEFINE FINALLY METHOD ***/
38+
/******************************************************************************/
39+
api.finally(function(req,res) {
40+
fakeDatabase.connected = false
41+
})
42+
43+
/******************************************************************************/
44+
/*** BEGIN TESTS ***/
45+
/******************************************************************************/
46+
47+
describe('Finally Tests:', function() {
48+
49+
it('Connected on first execution and after callback', function() {
50+
let _event = Object.assign({},event,{})
51+
52+
return new Promise((resolve,reject) => {
53+
api.run(_event,{},function(err,res) { resolve(res) })
54+
}).then((result) => {
55+
expect(result).to.deep.equal({ headers: { 'Content-Type': 'application/json' }, statusCode: 200, body: '{"method":"get","status":"ok","connected":true}' })
56+
expect(fakeDatabase).to.deep.equal({ connected: true })
57+
})
58+
}) // end it
59+
60+
it('Disconnected on second execution', function() {
61+
let _event = Object.assign({},event,{})
62+
63+
return new Promise((resolve,reject) => {
64+
api.run(_event,{},function(err,res) { resolve(res) })
65+
}).then((result) => {
66+
expect(result).to.deep.equal({ headers: { 'Content-Type': 'application/json' }, statusCode: 200, body: '{"method":"get","status":"ok","connected":false}' })
67+
})
68+
}) // end it
69+
70+
}) // end FINALLY tests

0 commit comments

Comments
 (0)