Lambda API: v0.6 Released

Posted in #lambda-api

Lambda API v0.6 is now available! This new version is all about making the serverless developer's life easier. Lambda API now supports both callback-style and async-await in route functions and middleware, letting the developer choose their preferred style. There are also several new ways to deal with HTTP methods including support for any() routes, a new head() convenience method, and the ability to assign multiple methods at once to the same route function. There's also a new route debugging feature that let's you return an array of routes and their methods OR you can log it in table form to the console.

Finally, two new convenience features were added to facilitate common serverless use cases. The first is preliminary support for Etag , which allows you to save bandwidth by using the browser's cache to serve unchanged data. And Lambda API now automatically parses Authorization headers for you!

NPM: https://www.npmjs.com/package/lambda-api

GitHub: https://github.com/jeremydaly/lambda-api

Support for callback-style and async-await

Lambda API now supports both callback-style and async-await for returning responses to users. The RESPONSE object has several callbacks that will trigger a response (send(), json(), html(), etc.) You can use any of these callbacks from within route functions and middleware to send the response:

javascript
api.get('/users', (req,res) => { res.send({ foo: 'bar' }) })

You can also return data from route functions and middleware. The contents will be sent as the body:

javascript
api.get('/users', (req,res) => { return { foo: 'bar' } })

Async/Await

If you prefer to use async/await, you can easily apply this to your route functions.

Using return:

javascript
api.get('/users', async (req,res) => { let users = await getUsers() return users })

Or using callbacks:

javascript
api.get('/users', async (req,res) => { let users = await getUsers() res.send(users) })

Promises

If you like promises, you can either use a callback like res.send() at the end of your promise chain, or you can simply return the resolved promise:

javascript
api.get('/users', (req,res) => { getUsers().then(users => { res.send(users) }) })

OR

default
api.get('/users', (req,res) => { return getUsers().then(users => { return users }) })

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.

New HTTP Method Controls

The METHOD method now accepts an array (or list) or methods. This lets you assign multiple methods to the same handler.

javascript
api.METHOD(['post','put'],'/users', (req,res) => { // do something on POST -or- PUT }) api.METHOD('post,put,patch','/users', (req,res) => { // do something on POST -or- PUT -or- PATCH })

All GET methods have a HEAD alias that executes the GET request but returns a blank body. GET requests should be idempotent with no side effects. The new head() convenience method can be used to set specific paths for HEAD requests or to override default GET aliasing.

javascript
api.get('/users', (req,res) => { res.send('This is the GET request') }) api.head('/users', (req,res) => { // This will override the /users route for HEAD requests // For example, I can return different headers })

Routes that use the any() method or pass ANY to METHOD, will respond to all HTTP methods. Routes that specify a specific method (such as GET or POST), will override the route for that method. For example:

javascript
api.any('/users', (req,res) => { res.send('any') }) api.get('/users', (req,res) => { res.send('get') })

A POST to /users will return "any", but a GET request would return "get". Please note that routes defined with an ANYmethod will override default HEAD aliasing for GET routes.

Debugging Routes

Lambda API has a new routes() method that can be called on the main instance that will return an array containing the METHOD and full PATH of every configured route. This includes base paths and prefixed routes, making debugging your routes super simple.

javascript
const api = require('lambda-api')() api.get('/', (req,res) => {}) api.post('/test', (req,res) => {}) api.routes() // => [ [ 'GET', '/' ], [ 'POST', '/test' ] ]

You can also log the paths in table form to the console by passing in true as the only parameter.

javascript
const api = require('lambda-api')() api.get('/', (req,res) => {}) api.post('/test', (req,res) => {}) api.routes(true) // Outputs to console ╔═══════════╤═════════════════╗ ║ METHODROUTE ║ ╟───────────┼─────────────────╢ ║ GET/ ║ ╟───────────┼─────────────────╢ ║ POST/test ║ ╚═══════════╧═════════════════╝

Etag Support

You can now generate Etags for any response sent by Lambda API. By calling res.etag(true) on the RESPONSE object before returning a response, Lambda API will generate an Etag based on the body and return the appropriate header. If subsequent requests contains an If-No-Match header that matches the generated Etag, a 304 Not Modified response will be returned with a blank body. This is a great way to avoid sending unchanged data back to the browser.

There is more work to be done with Etags and caching, such as concurrency control, but this first step can dramatically reduce the amount of bandwidth needed to transfer data.

Automatic Authorization Header Parsing

Yup, I'm excited too! No more stripping out Bearer tokens. Lambda API will automatically handle a number of schemas including Bearer, Basic, OAuth, and Digest. The req.auth will return an object with the type of schema and the value that was send with it. But there's more. For the Basic schema, the object is automatically decoded and extended with additional fields for username/password. For the OAuth schema, the object is extended with key/value pairs of the supplied OAuth 1.0 values. I know this will make my life easier.

Upgraded Route Processing & Optimizations

In addition to the features above, effort was put into upgrading the internal route processing engine. The switch to async/await has simplified the flow dramatically, which speeds up processing time. However, removing the promise chains required changes to the flow control. The internal flow now manages an execution state to ensure proper behavior for middleware, error handling and route functions. This new structure has greatly improved error catching and strict callback termination.

Finally, internal references were cleaned up to avoid any cross-contamination of objects. The REQUEST and RESPONSE objects were completely decoupled from the main API instance to avoid Lambda from inadvertently freezing any data from previous executions. Only the API settings and route configuration will be reused on warm invocations.

Release Notes:

Feature Release

v0.6 adds a number of enhancements to route processing including support for both callback-style and async-await responses. Plus added Etag support, advanced method control with any(), head() and multi-method assignments, authorization parsing, and new route debugging features.

Etag Support

  • Close #22 by adding preliminary etag support bab5ba8
  • Add documentation for etag() c2fa313

Method Control Enhancements

  • Close #35 by adding head convenience method and updating HEAD aliasing befc95c
  • Documentation for head() convenience method b674c15
  • Close #31 by adding support for ANY method; reprioritize HEAD aliasing 86b529e
  • Documentation for any() method a4323d7
  • Close #32 by looping methods 20f3164
  • Update documentation with multi-method info bc3df07

Authorization Header Parsing

  • Close #40 by adding automatic authorization header parsing a35e3d8
  • Add documentation for new auth value 6527a9d

Route Debugging

  • Close #33 by adding a routes() method for displaying routes b5a48ce
  • Add documentation for routes() method c40d26c

Async/Await Response Support

  • Add async/await callback styles 2f674d6
  • Add documentation for callback-style and async-await support d130690
  • Documentation updates to middleware and error handling 7b01883

General Updates/Maintenance

  • Consolidate util calls c8a8c2e
  • Add patch tests 26a4d1f
  • Decouple API, request, and response to remove potential variable cross-contamination ed1f1b8
  • Add Table of Contents to readme 7c1dc43, 8ac2c86

Full Release Notes: https://github.com/jeremydaly/lambda-api/releases/tag/v0.6.0

NPM: https://www.npmjs.com/package/lambda-api

GitHub: https://github.com/jeremydaly/lambda-api

Comments are currently disabled, but they'll be back soon.