Serverless Backends With AWS Cloud: API Gateway And You

Syncing The Gateway

The api gateway has two things you should know about it.

  1. Integration Response manipulation is a twisted nightmare when combined with regexes if you aren’t very meticulous.
  2. It has no built-in version control of any kind.

We are going to use it manage our lambdas. Let’s begin.

If you’re joining partway, please read this series from the intro article, serverless-backends-with-aws-cloud-intro.

After each time that you successfully deploy and test a stage (more on that in a second), I am assuming that you are wisely exporting that stage as a swagger/yaml file and saving that in your version control from your local machine. Version control, every time. It won’t save your files from being seemingly randomly deleted, but it can make reconstruction much faster.

We are going to make a gateway that points to multiple versions of a lambda function (our staging and production aliased versions that we made last time). This will require the use of the AWS CLI and stage variables.

Open the API gateway tab. Click get started.

Click the New API radio button on the top of the page.
This api is going to handle all of the calls for our site (email, twitter, etc), so let’s call it something that we want to use for our site. I’ll call mine services-api (you can call it anything, though).

Click Create API.

Click on our newly-created services-api. Click the resources button. Your screen should look like this.

api gateway new api screen

Click on Create Resource and type api in the resource path. Then click the blue Create Resource button.

With our newly-created api resource selected, create another resource. Your screen should look like this (note the default Resource Path choice is automatically proceeded by /api/. This is good).

create API Gateway resource menu

for the resource name, write email. Create Resource.

Select the newly-created email resource, then click create method and choose POST from the dropdown.

API Gateway POST menu dropdown

Click the checkmark to confirm. For integration type, choose lambda function. Leave the checkbox unticked and choose the region where your lambda is. For the lambda function name, type email_service:${stageVariables.alias} and click save. DO NOT PANIC.

What you are seeing is AWS saying that you must manually approve certain API Gateway and Lambda connections. Unfortunately, because we want the staging API to go to our staging-aliased lambdas, and the production api to go to our production lambdas, we need to save the lambda alias in an stage-level variable and use that to dynamically call the appropriate lambdas. If that sounds very confusing, it’s because it is. When you see it, it will become much clearer. Because this could be used to let any stage call any lambda, we have to go in and manually approve which aliases are allowed to be called from our stages. Let’s do that now.

Install, if you have not already, your AWS CLI tools (google it for your machine, it is very straightforward). After you’ve done that (and configured them), copy that big blurb of panic text in the dark gray box into your terminal, but don’t hit enter just yet. Change the part that says email_service:${stageVariables.lambdaAlias} to email_service:staging and hit enter. You should see some output that starts with the word Statement. Paste the same code again / hit up to access previous input, and now change it to read email_service:production. Hit enter again. Observe again response that starts with statement.

Now we’ve made the basic connection to our lambda and we need to configure a bunch of stuff before we can test it.

Back in the AWS panel, after you clicked okay to confirm that you did the manual confirmation, click on the post section under email. You should see this screen:

~API Gateway General Screen Overview

Click on Integration Request in the upper-right hand corner. Click the Body Mapping Templates dropdown and then change the Request body passthrough option to When there are no templates defined (recommended).

Click the blue + to add a mapping type.
I am making the assumption that your site is stored in static files in S3 and configured to serve content that way, so we will need application/x-www-form-urlencoded. If you expect JSON here, you can use application/json here, but then you probably don’t want to return 301 redirects either because it might be AJAX and need to edit your code appropriately.

Add the application/x-www-form-urlencoded and click the check. Scrolling down slightly, you will see a drop-down box that says Generate template. Set it to Method Request Passthrough and hit save.

Go back to the screen in the screenshot above (Method Execution panel), and click Method Response.
Click add response, and type in 301. Click the check mark. Then click the drop-down arrow that appears next to 301. Click add header, and type Location. Click the check mark.

Go back to the method execution panel again, and click Integration Response. Delete the existing response, then click Add integration response.

For the lambda error regex, write ^Email.MovedPermanently.*(source). You could write a host of other regexes depending on what you want to capture. In English, that method was what AWS officially recommends and the only I could find, but if you aren’t going to have multiple types of redirects/errors, .* works just fine as a regex (source).
For the method response status, choose the 301 that we made earlier.
Save, then expand the drop-down of our newly-created Integration Response. Under Header Mappings, where it says Response header with a value of Location, write in the value box integration.response.body.errorType. Click the check box, then the blue save button.

Go back to the Method Execution Panel, and change the drop-down inside Integration Response for HTTP status patter to the regex we just made (you may need to refresh the page).

Click the actions drop-down:

API Gateway actions dropdown

Click Deploy API. In the popup, under Deployment stage we’re going to select [New Stage]. For stage name, type Staging. For the descriptions, whatever you please. Hit deploy.

You will now see the staging stage. Click the Stage Variables tab. Click add stage variable. For Name, type alias. For Value, type staging. Click the checkmark.

This is where our email_service:${stagingVariables.alias} comes into play from earlier. This is how we tell the staging API to call email_service:staging alias.

Click Resources on the left-hand side, then Actions, then deploy API. Click new stage again, and set the name to production. Go Stage Variables, click Add Stage Variable, and use alias and production for the key and value. Note: Whenever you redeploy, you don’t have to reset stage variables.

This should conclude our setup, so let’s back this up to a yaml file. We actually also have the option of backing it up as JSON, but (and I kid you not) because we didn’t select application/json as our mapping type, it breaks the API if we try to restore from that file. No warnings, no errors, just breaks. If that is not your experience, please let me know; I’d hate to be bad-mouthing the API gateway if it was only my error.

Go to the export tab, click Export as Swagger + API Gateway Extensions, and copy the yaml and paste it in version control. You can restore from this if you ever need to by clicking resource -> actions -> import API.

We now have our api gateway setup. Let’s test it: Fire up Postman.

If you want to see the URL you need to post to, simply click Stages on the left-hand side, then click the stage you are interested in. In that drop-down, click the green POST method under /api/email. The link next to Invoke URL is what you need to post to. In Postman, set your body to x-www-form-urlencoded, then for your key write email and the value is whatever test email you want to confirm with.

Send, and you should get a glorious redirect. If you don’t see the html for your website callback in the redirect, observe the following:

Response of missing authentication token -> URL is mistyped or https errors (should be no https errors possible yet, so almost always the url at this stage)
Internal server error but lambda works (You have logs and an email) -> API integration response regex or location mapping for the header has a typo.
Internal server error and no email -> ??? If you have this but your test for the lambda we built last chapter works, something went really, really wrong and you might want to redo a lot of this chapter.
That concludes the API gateway connection part! If you send a post to the staging vs production, it should call different lambdas!

Next, we’ll set up cool twitter stuff to tweet in real time and follow some twitter accounts.