Lambda API: v0.6 Released
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:
javascriptapi.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:
javascriptapi.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
:
javascriptapi.get('/users', async (req,res) => { let users = await getUsers() return users })
Or using callbacks:
javascriptapi.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:
javascriptapi.get('/users', (req,res) => { getUsers().then(users => { res.send(users) }) })
OR
defaultapi.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.
javascriptapi.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.
javascriptapi.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:
javascriptapi.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 ANY
method 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.
javascriptconst 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.
javascriptconst api = require('lambda-api')() api.get('/', (req,res) => {}) api.post('/test', (req,res) => {}) api.routes(true) // Outputs to console ╔═══════════╤═════════════════╗ ║ METHOD │ ROUTE ║ ╟───────────┼─────────────────╢ ║ 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
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