lambda-proxy-utils

Lambda Proxy event helpers

Usage no npm install needed!

<script type="module">
  import lambdaProxyUtils from 'https://cdn.skypack.dev/lambda-proxy-utils';
</script>

README

lambda-proxy-utils

npm version Build Status Coverage Status Dependency Status Standard - JavaScript Style Guide

Lambda event helpers for AWS API Gateway lambda-proxy integration

Install

npm install --save lambda-proxy-utils

Update for version 2+

Node 4 is unsupported.

Update for version 1.4.0

AWS Lambda doesn't allow arrays for headers, so this is the hack way of returning multiple cookies per this thread: https://forums.aws.amazon.com/thread.jspa?threadID=205782

Basically you need to set multiple varations of Set-Cookie on the headers response object passed to the lambda callback like:

const response = {
  body: 'something',
  headers: {
    'Content-Type': 'text/plain',
    'Set-Cookie': 'some=cookie; Path=/',
    'Set-cookie': 'another=cookie; Path=/',
    'SEt-cookie': 'and_another=cookie; Path=/',
  },
  statusCode: 200
}

Using binary-case, we can generate 512 variations of Set-Cookie, so there's a hard limit, but hopefully you aren't setting 512 cookies.

Request

Takes an API Gateway lambda proxy integration event and returns an object that is similar to an express.js Request object.

// Example API Gateway proxy integration event passed to lambda
{
  "resource": "/api/pipe/{pathParam}",
  "path": "/api/pipe/hooray/",
  "httpMethod": "GET",
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate, sdch, br",
    "Accept-Language": "en-US,en;q=0.8",
    "Cache-Control": "no-cache",
    "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": "some=thing; testbool=false; testnull=null",
    "Host": "services.cheekyroad.com",
    "Pragma": "no-cache",
    "Referer": "https://cheekyroad.com/paht/?cool=true",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36",
    "Via": "1.1 1a1a1a1.cloudfront.net (CloudFront)",
    "X-Amz-Cf-Id": "2b2b2b2b2==",
    "X-Forwarded-For": "111.111.111.111, 222.222.222.222",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "queryStringParameters": {
    "et": "something"
  },
  "pathParameters": {
    "pathParam": "hooray"
  },
  "stageVariables": null,
  "requestContext": {
    "accountId": "111111111111",
    "resourceId": "blah",
    "stage": "dev",
    "requestId": "08e3e2d0-daca-11e6-8d84-394b4374a71a",
    "identity": {
      "cognitoIdentityPoolId": null,
      "accountId": null,
      "cognitoIdentityId": null,
      "caller": null,
      "apiKey": null,
      "sourceIp": "111.111.111.111",
      "accessKey": null,
      "cognitoAuthenticationType": null,
      "cognitoAuthenticationProvider": null,
      "userArn": null,
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36",
      "user": null
    },
    "resourcePath": "/api/pipe/{pathParam}",
    "httpMethod": "GET",
    "apiId": "cdcd4"
  },
  "body": null,
  "isBase64Encoded": false
}

const Request = require('lambda-proxy-utils').Request

module.exports.lambdaHandler = function(event, context, callback) {
  const req = new Request(event)
  req.ip // '111.111.111.111'
  req.userAgent // 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36'
  
  // Get's a field value in the order of query string param -> cookie -> header
  req.get('host') // 'services.cheekyroad.com'
  req.get('testnull') // null
  
  // Or be specific
  req.getHeader('x-forwarded-proto') // 'https'
  
  // Check the type
  req.is('html') // false
  
  // Get an AWS API Gateway requestContext property
  req.context('requestId') // '08e3e2d0-daca-11e6-8d84-394b4374a71a'
  
  // Get the unmodified Lambda Proxy event
  req.getLambdaEvent()
}

Response

Creates an express.js-like Response object, and outputs the API Gateway response format

const Response = require('lambda-proxy-utils').Response

module.exports.lambdaHandler = function(event, context, callback) {
  const res = new Response()
  // stringifies objects and set correct content type header
  callback(null, res.send({ some: 'object' }))
   /*
    {
      statusCode: 200,
      headers: {
          'Content-Type': 'application/json'
      },
      body: '{ "some": "object" }'
    }
   */
  
  // Support for CORS
  const res = new Response({ cors: true })
  callback(null, res.send({ some: 'object' }))
  /*
    {
      statusCode: 200,
      headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*'
      },
      body: '{ "some": "object" }'
    }
   */
   
  // Add a cookie
  const res = new Response()
  res.cookie('cookie', 'monster')
  callback(null, res.send({ some: 'object' }))
  /*
    {
      statusCode: 200,
      headers: {
          'Content-Type': 'application/json',
          'Set-Cookie': 'cookie=monster; Path=/'
      },
      body: '{ "some": "object" }'
    }
  */
  
  // Add a header
  const res = new Response()
  res.set('X-Random-Header', 1)
  callback(null, res.send({ some: 'object' }))
  /*
    {
      statusCode: 200,
      headers: {
          'Content-Type': 'application/json',
          'X-Random-Header': '1'
      },
      body: '{ "some": "object" }'
    }
  */
}

Contributing

I'd happily welcome pull requests. I've chosen to use Standard as the style with a few slight modifications. I'd like to keep the code coverage as high as possible.

Credits

I borrowed a lot from express