Aws lambda + api gateway

The road to success is certainly treacherous and unpaved when using AWS’ stuff. The cultural misappropriation of MSFT’s demo-ware is blatant. Yet, once you know the ins and outs, you can get stuff done.

So I had a case of a bunch of apis that would be internally used, not critical and would make no sense to provision a VM for that. To be more specific, it is used to collect perf tests results and then to display them in different ways.

Best tool for the job: serveless.

AWS lambda 

Amazon’s offering where you upload code and pay as it is used. Note though, that your code isn’t automatically exposed to the outside world.

AWS API Gateway

Bells and whistles to expose an endpoint to the outside world, secured or not, and mapping the incoming request to inside AWS (or another endpoint) including a lambda function.

First, use Apex

Apex will save you a lot of time deploying functions, and it’s convention on how to organize things (in folders, cascading config, etc) is a time saver.

Testing the functions

When testing within the aws console, keep an eye on the cloud watch for the log stream. Define a test input and run. All good? Time to expose it.

Exposing the endpoints

Two ways to do that:

  • Within the function, click on Triggers and add a API Gateway trigger.
  • Alternatively, go to the API Gateway console and define the resources and methods, and then map the resources to the lambda functions.

This turned out to be the tricky part in my short experience. Put it this way: lambda functions dont know about HTTP, and that’s ok. So on the API Gateway console you map parts of your http into the json your function expects.

When clicking on a http method, you’ll see Method Request -> Integration Request -> Lambda -> Integration Response -> Method Response.

Let’s break this down:

  • Method Request: the incoming http part of the equation. Here you have the opportunity to declare query strings params, headers and models (if you want document your api and|or create a client for it) and their semantics.
  • Integration Request: this is key. Lambda doesnt know about http, so here you have the opportunity to get info from the http request, and map into the json your function expects.
  • Integration Response: same thing on the opposite direction
  • Method Response: ditto

To use mapping, disable the “request body passthrough” and add a content type. Note, this will only work for POST, PUT, etc, in other words, requests with a body, thus where Content-Type is applicable.

Add a content type (very likely to be application/json).

Mapping is done by using a Velocity template. Check this out as an example to collect everything. In my case, I just wanted a param from the query string, so I used:

{ “myparamname”: “$input.params(‘querystringkeyname’)” }

Ready to test? You can test internally by using the gateway “Test” function. but if you want to use Postman or something else, then:

Deploy your api

You can create different “stages” (test, staging, production) and deploy api there. Once there, the urls are fixed. Changes to mapping and other configuration will require a re-deploy.

Annoyances

I’ve bumped into situations where I couldn’t delete methods or resources, even after deploying the new trimmed one, deleted ops would still show up.

The solution? Deleting the whole deployed api. The problem with that is that a new deploy comes with a new URL. It’s ok for us since we only use this internally, but in production this could be a huge headache.

Update

See Damien’s notes on the security issues with json mapping