
Security News
Meet Socket at Black Hat and DEF CON 2025 in Las Vegas
Meet Socket at Black Hat & DEF CON 2025 for 1:1s, insider security talks at Allegiant Stadium, and a private dinner with top minds in software supply chain security.
lambda-api
Advanced tools
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.
const API = require('lambda-api') // API library
// Init API instance
const api = new API({ version: 'v1.0', base: 'v1' });
api.get('/test', function(req,res) {
res.status(200).json({ status: 'ok' })
})
module.exports.handler = (event, context, callback) => {
// Run the request
api.run(event,context,callback);
} // end handler
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:
{
"resource": "/v1/posts",
"path": "/v1/posts",
"httpMethod": "GET",
"headers": {
"Authorization": "Bearer ...",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-us",
"cache-control": "max-age=0",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Cookie": "...",
"Host": "...",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) ...",
"Via": "2.0 ... (CloudFront)",
"X-Amz-Cf-Id": "...",
"X-Amzn-Trace-Id": "...",
"X-Forwarded-For": "xxx.xxx.xxx.xxx",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": {
"qs1": "q1"
},
"stageVariables": null,
"requestContext": {
"accountId": "...",
"resourceId": "...",
"stage": "prod",
"requestId": "...",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"apiKey": null,
"sourceIp": "xxx.xxx.xxx.xxx",
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "...",
"user": null
},
"resourcePath": "/v1/posts",
"httpMethod": "GET",
"apiId": "..."
},
"body": null,
"isBase64Encoded": false
}
The API automatically parses this information to create a normalized REQUEST
object. The request can then be routed using the APIs methods.
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.
const API = require('lambda-api') // API library
// Init API instance with optional version and base path
const api = new API({ version: 'v1.0', base: 'v1' });
Routes are defined by using convenience methods or the METHOD
method. There are currently five convenience route methods: get()
, post()
, put()
, delete()
and options()
. Convenience route methods require two parameters, a route and a function that accepts two arguments. A route is simply a path such as /users
. The second parameter must be a function that accepts a REQUEST
and a RESPONSE
argument. These arguments can be named whatever you like, but convention dictates req
and res
. Examples using convenience route methods:
api.get('/users', function(req,res) {
// do something
})
api.post('/users', function(req,res) {
// do something
})
api.delete('/users', function(req,res) {
// do something
})
Additional methods are support by calling the METHOD
method with three arguments. The first argument is the HTTP method, a route, and a function that accepts a REQUEST
and a RESPONSE
argument.
api.METHOD('patch','/users', function(req,res) {
// do something
})
The REQUEST
object contains a parsed and normalized request from API Gateway. It contains the following values by default:
version
: The version set at initializationparams
: Dynamic path parameters parsed from the path (see path parameters)method
: The HTTP method of the requestpath
: The path passed in by the requestquery
: Querystring parameters parsed into an objectheaders
: An object containing the request headersbody
: The body of the request.Content-Type
header is application/json
, it will attempt to parse the request using JSON.parse()
Content-Type
header is application/x-www-form-urlencoded
, it will attempt to parse a URL encoded string using querystring
route
: The matched route of the requestrequestContext
: The requestContext
passed from the API GatewayThe 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 for more information.
The RESPONSE
object is used to send a response back to the API Gateway. The RESPONSE
object contains several methods to manipulate responses. All methods are chainable unless they trigger a response.
The status
method allows you to set the status code that is returned to API Gateway. By default this will be set to 200
for normal requests or 500
on a thrown error. Additional built-in errors such as 404 Not Found
and 405 Method Not Allowed
may also be returned. The status()
method accepts a single integer argument.
api.get('/users', function(req,res) {
res.status(401).error('Not Authorized')
})
The header
method allows for you to set additional headers to return to the client. By default, just the Content-Type
header is sent with application/json
as the value. Headers can be added or overwritten by calling the header()
method with two string arguments. The first is the name of the header and then second is the value.
api.get('/users', function(req,res) {
res.header('Content-Type','text/html').send('<div>This is HTML</div>')
})
The send
methods triggers the API to return data to the API Gateway. The send
method accepts one parameter and sends the contents through as is, e.g. as an object, string, integer, etc. AWS Gateway expects a string, so the data should be converted accordingly.
There is a json
convenience method for the send
method that will set the headers to application\json
as well as perform JSON.stringify()
on the contents passed to it.
api.get('/users', function(req,res) {
res.json({ message: 'This will be converted automatically' })
})
There is also an html
convenience method for the send
method that will set the headers to text/html
and pass through the contents.
api.get('/users', function(req,res) {
res.html('<div>This is HTML</div>')
})
An error can be triggered by calling the error
method. This will cause the API to stop execution and return the message to the client. Custom error handling can be accomplished using the Error Handling feature.
api.get('/users', function(req,res) {
res.error('This is an error')
})
Path parameters are extracted from the path sent in by API Gateway. Although API Gateway supports path parameters, the API doesn't use these values but insteads extracts them from the actual path. This gives you more flexibility with the API Gateway configuration. Path parameters are defined in routes using a colon :
as a prefix.
api.get('/users/:userId', function(req,res) {
res.send('User ID: ' + req.params.userId)
})
Path parameters act as wildcards that capture the value into the params
object. The example above would match /users/123
and /users/test
. The system always looks for static paths first, so if you defined paths for /users/test
and /users/:userId
, exact path matches would take precedence. Path parameters only match the part of the path they are defined on. E.g. /users/456/test
would not match /users/:userId
. You would either need to define /users/:userId/test
as its own path, or create another path with an additional path parameter, e.g. /users/:userId/:anotherParam
.
A path can contain as many parameters as you want. E.g. /users/:param1/:param2/:param3
.
Wildcard routes are supported for methods that match an existing route. E.g. options
on an existing get
route. As of now, the best use case is for the OPTIONS method to provide CORS headers. Wildcards only work in the base path. /users/*
, for example, is not supported. For additional wildcard support, use Path Parameters instead.
api.options('/*', function(req,res) {
// Do something
res.status(200).send({});
})
The API supports middleware to preprocess requests before they execute their matching routes. Middleware is defined using the use
method and require a function with three parameters for the REQUEST
, RESPONSE
, and next
callback. For example:
api.use(function(req,res,next) {
// do something
next()
})
Middleware can be used to authenticate requests, log API calls, etc. The REQUEST
and RESPONSE
objects behave as they do within routes, allowing you to manipulate either object. In the case of authentication, for example, you could verify a request and update the REQUEST
with an authorized
flag and continue execution. Or if the request couldn't be authorized, you could respond with an error directly from the middleware. For example:
// Auth User
api.use(function(req,res,next) {
if (req.headers.Authorization === 'some value') {
req.authorized = true
next() // continue execution
} else {
res.status(401).error('Not Authorized')
}
})
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.
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:
api.finally(function(req,res) {
// close unneeded database connections and perform clean up
})
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.
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.
api.use(function(err,req,res,next) {
// do something with the error
next()
})
The next()
callback will cause the script to continue executing and eventually call the standard error handling function. You can short-circuit the default handler by calling a request ending method such as send
, html
, or json
.
The API uses Bluebird promises to manage asynchronous script execution. Additional methods such as async / await
or simple callbacks should be supported. The API will wait for a request ending call before returning data back to the client. Middleware will wait for the next()
callback before proceeding to the next step.
CORS can be implemented using the wildcard routes feature. A typical implementation would be as follows:
api.options('/*', function(req,res) {
// Add CORS headers
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
res.status(200).send({});
})
Conditional route support could be added via middleware or with conditional logic within the OPTIONS
route.
Routes must be configured in API Gateway in order to support routing to the Lambda function. The easiest way to support all of your routes without recreating them is to use API Gateway's Proxy Integration.
Simply create one {proxy+}
route that uses the ANY
method and all requests will be routed to your Lambda function and processed by the lambda-api
module.
FAQs
Lightweight web framework for your serverless applications
The npm package lambda-api receives a total of 26,766 weekly downloads. As such, lambda-api popularity was classified as popular.
We found that lambda-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Meet Socket at Black Hat & DEF CON 2025 for 1:1s, insider security talks at Allegiant Stadium, and a private dinner with top minds in software supply chain security.
Security News
CAI is a new open source AI framework that automates penetration testing tasks like scanning and exploitation up to 3,600× faster than humans.
Security News
Deno 2.4 brings back bundling, improves dependency updates and telemetry, and makes the runtime more practical for real-world JavaScript projects.