In this lab, we will
- Set up a database
- Create two lambdas that create and retrieve data from a database
- Hook the lambdas up to REST methods
- Actually have everything working
While doing this, we will learn
- What RDS is and how to instantiate a database
- What a lambda function is and how to create one
- How to have your lambda talk to your database
- How to map REST requests to your lambdas
Everyone new to AWS spends a long time looking around in configuration files to get stuff to work. By doing a fairly useful thing like connecting REST to a database in a step-by-step way, I hope to have you avoid some of that first time frustration.
I need three things of you before we start the lab
- You all have to be able to log in to AWS Console. If you don't have an account, head to https://aws.amazon.com/ and hit Sign up. It takes a couple of minutes and requires personal details like credit card, but everything in this lab is free.
- Clone this repo to your personal computer.
- We will be zipping files, make sure you have some program that can create a .zip
I have prepared the lambda functions. The lambdas are written in Python and are located in the lambdas-folder in this repo. The files I wrote are called index.py
, the rest is libs. We won't talk about the lambda code very much in this lab, but you can totally check them out. They basically just validate the input and call the database.
Sign in to AWS at https://console.aws.amazon.com/. The sign in option is in the top right corner. We are going to the Service called RDS.
RDS stands for Relational Database Service.
Click Services in the top menu bar, then click RDS in the menu.
In the RDS page, click the big orange button called Create function.
Choose MySQL
as database engine. For this lab, we're only using the free tier available stuff, so check the checkbox called Only enable options elligible for frie RDS Free Usage Tier
. Click Next.
Leave the top of the page as is, and scroll down to the bottom of the page.
Go to the section Function code
Field | Value |
---|---|
DB instance identifier | aws-lambda-lab |
Master username | root |
Password | your-super-safe-password (Whatever you like, but remember it) |
We're going to have the database be publically accessible to make this lab a little easier to setup.
Field | Value |
---|---|
Public accessibility | Yes |
Specify the database name
Field | Value |
---|---|
Database name | messages |
Scroll down and click Create database
In the next page, click View DB instance details
The database is being created and backed up. Refresh the page and wait for the status to become available
.
Go to the Details section
Make sure that the status is available
and take note of the endpoint.
The endpoint will look something like aws-lambda-lab.your-unique-identifier.us-east-2.rds.amazonaws.com
Open up your favourite MySQL client. All the examples I use is with the unix terminal one, mysql
.
Remember to replace the host with your actual host. You will need your password, in the example it was your-super-safe-password
.
mysql -h aws-lambda-lab.your-unique-identifier.us-east-2.rds.amazonaws.com -u root -p messages
If your not in the database messages
, go there
use messages
Create the following table:
create table messages (
id int primary key auto_increment,
username varchar(255) not null,
message text not null,
created_time datetime not null default current_timestamp()
);
The POST lambda is expecting a stored procedure insert_message
to call to insert new messages.
delimiter #
create procedure insert_message(
in p_username varchar(255),
in p_message text
)
begin
insert into messages (username, message) values (p_username, p_message);
select id, username, message, created_time from messages where id=last_insert_id();
end
#
delimiter ;
Try the procedure out:
call insert_message('anon', 'Testing the stored procedure');
-- output:
-- +----+----------+------------------------------+---------------------+
-- | id | username | message | created_time |
-- +----+----------+------------------------------+---------------------+
-- | 1 | anon | Testing the stored procedure | 2018-11-15 17:57:40 |
-- +----+----------+------------------------------+---------------------+
-- 1 row in set (0.34 sec)
--
-- Query OK, 0 rows affected (0.34 sec)
If you haven't already, clone this repo to your computer.
git clone https://github.com/simonolander/aws-lambda-lab.git
cd aws-lambda-lab
There is a folder called lambdas
in the root of the repo. It contains our two additional folders containing the code for our lambdas, getMessages
and postMessage
.
.
├── LICENCE and README and stuff...
└── lambdas
├── getMessages
└── postMessage
Most of the contents in the folders are libraries for communicating with the database. The entry points for the lambdas (and the only code that isn't a lib) are in the files getMessages/index.py
and postMessage/index.py
.
The lambdas are not yet complete; they are missing credentials for the database. Create a file called rds_config.py
and add the same information as below, but with your own rds_host
and rds_password
.
rds_host = "aws-lambda-lab.your-unique-identifier.us-east-2.rds.amazonaws.com"
rds_username = "root"
rds_password = "your-super-safe-password"
rds_db_name = "messages"
Place a copy of rds_config.py
in lambdas/getMessages
and lambdas/postMessage
respectively. You should have the following structure.
.
└── lambdas
├── getMessages
│ ├── ...
│ ├── index.py
│ └── rds_config.py
└── postMessage
├── ...
├── index.py
└── rds_config.py
If you have python3 on your computer, you can test that the lambda works by running
cd lambdas/getMessages/
python3 -c "from index import handler; print(handler({'params': {'querystring': {'limit': '1'}}}, {}));"
# output
# [{'id': 17, 'username': 'sios', 'message': 'Inserting a message from the gateway api section', 'created_time': '2018-11-04 20:42:30+01:00'}]
If you get get an error saying ModuleNotFoundError: No module named 'rds_config', make sure that you copied rds_config.py
to the right place.
The folders need to be zipped before we can upload them to AWS. You need to zip the entire contents of getMessages
and postMessage
to two separate zip files. Make sure to include the contents and subfolders recursively, but do not include the root folders getMessages
and postMessage
themselves. You can zip using whatever tool you like, I usually do
cd lambdas/getMessages
zip -r ../getMessages.zip *
cd ..
cd postMessage
zip -r ../postMessage.zip *
You should have two zip files, one for each code folder. The names of the zip files are not important.
.
└── lambdas
├── getMessages
├── getMessages.zip
├── postMessage
└── postMessage.zip
The zips should be about 2.8 MB in size. If they are smaller, verify that you zipped recursively.
du -h lambdas/*.zip
# 2.8M lambdas/getMessages.zip
# 2.8M lambdas/postMessage.zip
Click Services in the top menu bar, then click Lamdba in the menu. In the lambda page, click the big orange button called Create function.
Fill in the form for your function. We are doing getMessages
first.
Field | Value |
---|---|
Template | Author from scratch |
Name | getMessages |
Runtime | Python 3.6 |
Role | Create a custom role (if you already have an existing role, you can use that one) |
You will be taken to a window to create your role. Just leave everything as-is. The role will be called lambda_basic_execution
.
Click Allow
If you come back to the create function page, select `lambda_basic_execution and click Create function.
Field | Value |
---|---|
Role | Choose an existing role |
Existing role | lambda_basic_execution |
You will be in a new view showing you a bunch of stuff about your lambda. It's a functioning lambda, but it doesn't do anything useful. We're going to upload the code from getMessages.zip
.
Go to the section Function code
Field | Value |
---|---|
Code entry type | Upload a .zip file |
Runtime | Python 3.6 |
Handler | index.handler |
Function package | getMessages.zip |
Click Save in the top right corner. It's going to take a couple of seconds.
Go back to Functions and create a new lambda the same way. This time call it postMessage
. Use the same role lambda_basic_execution
as you used last time. When uploading the function code for this lambda, upload postMessage.zip
instead of the first zip file. Click Save.
Click Services in the top menu again. This time go to API Gateway. If you see a welcome screen, click Get started.
Fill out the API form.
Field | Value |
---|---|
Template | New API |
API name | messages |
Description | Some description |
Endpoint type | Regional |
Click Create API
Select Create Method from the Actions dropdown.
Select GET from the small dropdown under Resources, then save by clicking the small checkmark next to the dropdown.
Field | Value |
---|---|
Enter Lambda Function | getMessages |
Click Save
You can see four boxes now where we will configure the request and response mappings to the lambda. We will visit all four of them in the following order:
- Method Request
- Integration Request
- Method Response
- Integration Response
Go to Method Request
Expand URL Query String Parameters and add a new query string:
Field | Value |
---|---|
Name | limit |
Required | false |
Caching | false |
Go back to Method Execution, then to Integration Request
Expand URL Query String Parameters add a new entry:
Field | Value |
---|---|
Name | limit |
Mapped from | method.request.querystring.limit |
Caching | false |
A bit down but still in Integration Request, expand Mapping Templates. We're going to create a new mapping to pass all the arguments to the lambda.
Field | Value |
---|---|
Request body passthrough | When there are no templates defined |
Add a new mapping template
Field | Value |
---|---|
Content-Type | application/json |
Generate template | Method Request passthrough |
Click Save
Go back to Method Execution, then to Method Response
Add a new HTTP Status response:
Field | Value |
---|---|
Status code | 400 |
Go back to Method Execution, then to Integration Response
Add a new integration response:
Field | Value |
---|---|
Lambda Error Regex | Bad Request.* |
Method response status | 400 |
Content handling | Passthrough |
Go back to Method Execution, then to Test
Test the method, try changing the limit to different values.
Create a new method POST the same way you created the GET method. Point it to the lambda postMessage
instead of the first lambda.
Under Integration Request, add the same request mapping as we did in GET, but leave the query string empty
Under Method Response, add status code 400 as we did in GET
Under Integration Response, add the same response for 400 Bad Request as we did in GET
Go to test and try it out! Remember to specify a request body with username
and message
, here is an example:
{
"username": "anon",
"message": "Shooting from the API Gateway test area."
}
Under the Actions dropdown where we created the GET and POST methods, click Enable CORS.
The API is not public yet, you need to deploy it to be able to access it outside AWS.
Click Deploy API under the Actions dropdown.
Give the stage a name, e.g. production
.
Click or copy the url at the top of the page.
Test it with GET and POST and various parameters. The GET is easiest to test from your browser. If you have curl, you can use the following line to test your POST. Remember to change the url to your url.
curl -d '{"username": "anon", "message": "hello"}' -H "Content-Type: application/json" -X POST https://your-lambda-id.execute-api.us-east-2.amazonaws.com/production