October 16, 2017

Lambda routing

When deploying a single Lambda function to handle your API you need a way of delegating those API requests to the various functions in your code. Most likely this will be decided based upon the verb and the path, as well as possibly the presence of path parameters. If you are already building a JavaScript application that leverages Express (or other framework) then there may be an existing library that binds your Express routes to inbound API Gateway requests.

Advantages of this model

This model has you deploying a single function so that you still get the benefit of Lambda’s on-demand computing resources, with the benefit of a single entry point, which makes it a little easier to reason about and write things like pre-filters or middleware.

Why not use a library?

Perhaps a better question is why use a library? – for something so simple there is no reason to bring on an external dependency that may fluctuate or bring with it a large dependency graph. Additionally, generalizing this approach may just make it less obvious what your code is doing.

Example Code (with comments)

"use strict";

const routes = {
  "/products/?": {
    "GET": listProducts,
    "POST": registerProduct,
  },
  "/products/search": {
    "GET": searchProducts,
  },
  "/drones/(.+)": {
    "GET": fetchProduct,
    "PUT": updateProduct,
    "DELETE": deleteProduct,
  },
  "/accounts/?": {
      "GET": fetchAccounts,
  },
  "/accounts/(.+)": {
      "POST": updateAccount,
      "DELETE": deleteAccount
  }
}

module.exports.router = (event, context, callback) => {
  for(var route in routes) {
    var re = new RegExp("^" + route + "$");
    if (re.test(event['path'])) {
      let handlers = routes[route];
      let httpMethod = event["httpMethod"];

      if (httpMethod in handlers) {
        return handlers[httpMethod](event, context, callback);
      }
    }
  }

  // Otherwise unknown route or method

  const response = {
    statusCode: 405,
    headers: {
      "Access-Control-Allow-Origin" : "*",
      "Access-Control-Allow-Credentials" : true
    },
    body: JSON.stringify({
      message: `Invalid HTTP Method: ${httpMethod}`
    }),
  };

  callback(null, response);
};