Moving a simple API to Amazon’s API Gateway
Last week, Amazon announced their new API Gateway. Among other interesting use cases, the one that attracted me was the ability to hook it up to a Lambda function. This can allow you to have an API without having to worry about scaling your infrastructure at all. I’ve been wanting to play with Lambda for awhile, but didn’t really have a good excuse to use it - until now.
I created AreThePlanetsAligned.com awhile ago as a simple way to see how long it would take to build a quick website/API and get it online. It was hosted on Heroku, which at the time had a very generous introductory plan that let you run small apps essentially free, forever. They’ve since modified their pricing a bit — free apps now must sleep for at least 6 hours a day. If you want even a small app up 24/7, you have to pay $7/month. Still quite generous, but that can add up for devs who, like myself, have several “hobby” apps lying around.
Most of my apps are constructed as an API first, with a web UI connecting to it. That approach makes it a bit easier to debug when something goes wrong. And now it makes it very straightforward to move my little apps to make use of Amazon’s API Gateway, and how the UI on S3. Here’s how I did moved AreThePlanetsAligned from Heroku to AWS.
Creating a new API
If you don’t have one already, you’ll need to sign up for an AWS account before you can create an API. Once you have that, log into the AWS console and click on the new API Gateway under Application Services. Click the Create API button, and fill out the API name and description.
The API Gateway will automatically create a Root resource for you. You can attach methods to this endpoint if you want, but I created a new child Resource under the root called “alignments”.
The new child resource shows up under the “/” (the root resource of your API). It doesn’t have any methods yet (like GET or POST); we’ll add those in a bit.
Creating an Access Policy in IAM
Before you can attach your API to a Lambda function you’ll need to setup a policy that will allow Lambda to execute code. This policy is defined in the Identity and Access Management (IAM) part of AWS. After you open IAM, click the Policies link in the navigation area.
After you’ve created the policy, you’ll need to create a Role to access that Policy. Back in IAM, click on the Roles link and then on the Create New Role button. You’ll be asked to provide a Role name, and then to attach a Policy to that Role.
AWS will then let you review the role before you click the final Create Role button.
Creating your Lambda Function
At this point, we have our API partially implemented and a Role ready to go. Now it’s time to create the brains of your API — the Lambda function that will get called whenever your API endpoint gets requested.
Back at the AWS console, click on the Lambda link under the Compute heading. Skip the Select Blueprint options, and you’ll land on the New Function page.
You’ll need to give the function a name, description, runtime (defaults to Node.js), and the code itself. You can edit the code inline if it’s straightforward and has no dependencies. If it’s more complex, you’ll need to upload a Zip file containing everything that it needs access to.
If you’re writing in Node.js, you’ll need to expose a “handler” method that Lambda knows to call. The default is index.handler, which in your code becomes “exports.handler”. You’ll also need to give this Lambda function a Role — the same one we created above. You can also modify the amount of memory available to the function and a timeout setting if you’d like. I stuck with the defaults of 128 MB and 3 seconds.
After you save the function you’ll be given a chance to Review it, and then to test it. This allows you to pass in some variables and see what the Lambda returns.
Adding an API Method
Now that the brains of our API are ready, we can hook our API up to the Lambda function.
Back in the API Gateway, click the Create Method button, select the HTTP method you need (I used GET), and click the tiny check mark when you’ve selected the one you want. You’ll be taken to the method Setup screen.
You’ll be asked for an Integration Type, in this case Lambda Function, and the name of the Function. When you click Save you’ll get a modal window asking you to “Add Permission to Lambda Function”. This gives the API Gateway permission to invoke your Lambda code, so click OK.
You’ll be taken to the Method Execution screen, which shows you exactly how a request will work from a Client, to your Lambda function, and back.
If everything looks in order, it’s time to deploy your API. You can deploy to different stages, named however you wish. You’ll likely want to deploy first to a Testing stage, and then in the future deploy to a Production stage if everything works all right.
After you deploy, you’ll be given an end point from which you can access your API. If your method is GET, you can likely call your resource from the browser (note you’ll need to modify the URL Amazon gives you by tacking on the resource name). Otherwise, you can curl it to be sure everything is working.
At this point, your API is working, but you may want to take some additional steps, likes supporting CORS so your API can be called from a browser and moving your static website to S3.
CORS Support for your API
From your Resource’s Method Execution screen, click on the Method Response box. Expand the “200” status, and click the Add Header button.
You’ll need to add the following headers:
When you’re done, return to the Method Execution screen, and click on the Integration Response box. Here’s where you’ll actually set the value of those headers, under the 200 response, like so:
- Access-Control-Allow-Headers = ‘Content-Type,X-Amz-Date,Authorization’
- Access-Control-Allow-Methods = ‘GET’
- Access-Control-Allow-Origin = ‘*’
You do need to put a single quote around the value of each header.
Hosting your Website with S3
Now that the brains of the API are inside the API Gateway, there’s no more need to have a web server just to host a static website. Instead, we’ll dump everything into S3, and let Amazon handle that for us, too!
Create a new Bucket in S3, and modify the Bucket Policy to make the contents GetObject action accessible to anyone. Amazon has an example policy you can use.
You’ll also need to expand the Static Website Hosting option and click the Enable website hosting option, and point it at your root document, such as index.html.
Then you can use the AWS CLI to sync your static contents to S3.
That’s it — a website and an API without any web servers. You can take it even further if your API is more complicated, by making use of AWS’s many other features like Dyanmo or CloudSearch. It’s amazon how you can create a very powerful, complicated service without having any servers. Now if Amazon would just write the code for you…