There comes a surreal moment in nearly every profession in which perspective violently forces itself into our self-awareness. People with cooler jobs probably have that moment when they save their first patient or launch their first rocket. For me, the idea of building an API was this moment in software development. All those past black boxes which spat out results your life depended on: we can make those now.

Feel free to remain unfazed by this as I'm sure most are... for those of us who can't remember how they became an "engineer" in the first place, API design feels like reaching a final frontier. Granted, this may happen at least 20 more times in your software career, so don’t pause too long now.

If you managed to catch the tutorial on setting up RDS on AWS, you're already a step ahead. We're going to make our way through this slowly, which is probably a good idea even if you've done this before. There are so many pitfalls and nuances in AWS's architecture that I'm not even sure I fully understand what's happening, even when everything works.

Quick Overview

Here are the services we'll be using to hook this baby up:

  • RDS: Amazon's cloud-hosted relational databases. These databases come preconfigured with an endpoint, which can be made accessible to other AWS services or even to external manipulation.
  • Lambda: Snippets of code which can be invoked without setting up a web server (hence: "serverless"). Lambda functions are intended to serve simple, specific functions (such as serving as the logic for an endpoint, for instance). Lambda functions play well with other AWS services: we'll be using this as the glue between our API and interacting with the Database.
  • API Gateway: Amazon's visual editor for creating an API. API Gateway allows developers to architect the structure and logic of APIs without having to worry about setting up routes via code.
  • IAM: Amazon's headache of a user & permissions manager. IAM is needed to specify exactly with AWS services have access to other services, which users are permitted to interact with your API, etc.

Gameplan

So here's the deal. Our RDS database will be where all the data we provide and receive will live. Lambda functions will be the snippets of code actually interacting with information from the database; all of our queries will be done through Lambda. API Gateway will control the "design" of the API, as in the structure of endpoints, their respective methods, and how all these should interact with Lambda.

It sounds simple enough, but the devil is in the details. And trust me, there are a lot of details.

Setting the Correct Role Permissions

Usually, I'd say we should jump into the fun stuff and deal with the details when we get to them. I won't let you steer down that road with AWS... let's avoid smashing our heads on keyboards where possible and kick things off slow.

If you were to attempt to create a Lambda function off the bat, the first prompt to appear would demand a "role" to be specified. Roles are one of the types of permission packages (?) we mentioned earlier. Roles limit exactly which services your Lambda function can interact with off the bat. Start with the wrong role, and you won't be able to do much of anything.

Head over the IAM console to set up an appropriate role:

What a God-awful way to handle permissions.
What a God-awful way to handle permissions

Let's pause for a moment to take this all in. You'll see we have users, groups, roles, policies and a whole bunch of other garbage. Policies can be attached to roles. Policies can also be attached to users, and also attached to groups. Users can be in groups. Wait, so what if a user has a bunch of policies, but then joins a group with a bunch of policies? What even is a "policy"? These are the real questions. The short answer is none of it makes sense; it's just extra job security for those who make it work.

Click on "Roles" in the sidebar. Create a role. Select "Lambda" and click next.

This interface only seems to get worse
This interface only seems to get worse

Ok cool. The role we're creating is basically just going to be a collection of permissions we can attached directly to the role. Go ahead and attach these:

  • AmazonVPCFullAccess
  • AmazonAPIGatewayInvokeFullAccess
  • AmazonRDSFullAccess
  • AWSLambdaFullAccess
  • CloudWatchLogsFullAccess

Save the role, and remember what you name it. You'll need it.

Getting Started with Lambda Functions

Go back to the Lambda console. It's game time. We're going to create a function from scratch (sadly, I haven't found any of the blueprints to be very useful just yet).

Ignore Amazon's silly Blueprints
Ignore Amazon's silly Blueprints

Under “runtime”, you’ll need to pick which programming language we’ll be writing our function in. I’m doing Python 3 because I don’t mess with semicolons, ya dig. Most people seem to stick with Node, which makes sense: Node is much faster at runtime, especially when you consider that AWS runs Node natively. The choice is your preference.

Aha, see the “Role” dropdown? This is what I warned you about. Select the role you just created earlier from existing roles.

Lambda Function Editor

Welcome to Lambda's web UI
Welcome to Lambda's web UI

Behold, the Lambda visual editor. That tree you're seeing is a representation of the integration this function will handle. The current function is the box top-middle, the trigger is on the left, and the list of potential AWS services we can touch is on the right; these were automatically populated by that role I forced you to create. You're welcome.

NOTE: The entire interface below this section depends on which service you've clicked in the tree. It's not the most intuitive at first. I have my Lambda function selected, so that's the interface I can interact with below.

Inline Code Editor

Create Lambdas via the browser UI or by uploading source via zip
Create Lambdas via the browser UI or by uploading source via zip

Real quick, we need to go over what each field here does. The dropdown currently set to "edit code inline" can be expanded, which gives you the option to upload a zip file of source code. THIS WILL DELETE ALL PREEXISTING WORK. They don't tell you that, hah. Ha hah. I recommend doing everything offline to be uploaded later - this needs to be done with python packages anyway.

Handler specifies which function should be called upon initialization. "lambda_function" is referring to the function, so "handler" here specifies that the function handler within lambda_function.py is what will get called upon execution.

Our Lambda’s VPC Settings

Scroll down until you hit this pretty little gem:

AWS is filled with complicated network concepts and zero attempts to explain them.
AWS is filled with complicated network concepts and zero attempts to explain them

We need to specify the VPC this function will interact with. If you created an RDS already, go ahead select the VPC you created. Add a bunch of subnets (whichever ones). Finally, select a security group. Remember that the permissions of this group determine whether or not your VPC is allowed to speak to this function. If you're struggling with this, check out the AWS MySQL post again. I'm not going to link it twice in one post, sorry. I have self-respect you know.

That's Enough For Now

There's a lot to take in when playing around in AWS. The combination of gibberish terminology and horrible documentation doesn't exactly make for solid user experience. If you're new to AWS and any of this seems frustrating, know it's supposed to be. Amazon owns you, and they hate you. Kind of like God.

I'd suggest messing around the interface, and maybe even check out API Gateway a bit to get a feel for how that stuff looks. They set you up with a cute demo to make you think it's going to be easy, so maybe you'll enjoy that. Next time, we're going to crank out some Lambdas.