[PRE] Embedded System #9 — Build a REST API in AWS
Hi, Safiq here again. Instead of jumping straight into project #9 which involves working with an API for my ESP32, I’ll be discussing the necessary prerequisites first. This includes constructing a REST API on AWS using services like EC2, RDS, Lambda, and API Gateway. So, let’s get started!
REST API
An API, or application programming interface, is a set of rules that define how applications or devices can connect to and communicate with each other. A REST API is an API that conforms to the design principles of the REST, or representational state transfer architectural style. For this reason, REST APIs are sometimes referred to RESTful APIs.
First defined in 2000 by computer scientist Dr. Roy Fielding in his doctoral dissertation, REST provides a relatively high level of flexibility and freedom for developers. This flexibility is just one reason why REST APIs have emerged as a common method for connecting components and applications in a microservices architecture.
(Source: IBM)
EC2 (Elastic Compute Cloud)
Link: https://ap-southeast-2.console.aws.amazon.com/ec2/home?region=ap-southeast-2#Instances:
Create an instance with Ubuntu 22.04 LTS as the OS.
Additionally, for added security, don’t forget to generate an RSA key pair to protect your SSH connection. Once your instance is created, you can view it in the EC2 console with the display shown below.
After that, just connect to your EC2. There are 2 ways that I recommend, which are EC2 instance connect (via browser) and SSH client (via terminal).*
RDS (Relational Database Service)
Link: https://ap-southeast-2.console.aws.amazon.com/rds/home?p=rds&cp=bn&ad=c®ion=ap-southeast-2
Create a database instance named sensor-bmp280 with MySQL as the DBMS (Database Management System).
In the Connectivity section, click on the “Connect to EC2 computing resources” and choose the instance you have created before. This will make your database instance more secure, and the created database instance will be shown as below.
After you have created your database instance, go back to your EC2 instance and install MySQL by typing sudo apt install mysql-client-core-8.0
in the terminal. Then, from there, you can connect to your MySQL using mysql -h <your_database_endpoint> -P 3306 -u admin -p
. You can get the endpoint by clicking on your database instance in the image above. Mine is sensor-bmp280.c1hychjmjdhi.ap-southeast-2.rds.amazonaws.com. After you connect, just create your database using CREATE DATABASE sensor_bmp280;
.
Lambda
Link: https://ap-southeast-2.console.aws.amazon.com/lambda/home?region=ap-southeast-2#/functions
Now it’s time to create two functions: one for responding to GET requests (named get_sensor_bmp280) and another for handling POST requests (named post_sensor_bmp280). To make it easier to understand, we’ll be using Python to write both functions.
For each function, you’ll need to configure the VPC (Virtual Private Cloud) to the default. Then, choose only subnets with names that contain “RDS”. You’ll need to choose at least 2 subnets. For the security group, choose 4 of them: ec2-rds-1, ec2-rds-2, rds-ec2–1, and rds-ec2–2.
Because we’ll be using the pymysql package to connect to MySQL, you’ll need to add a layer to your function. You can access this layer in the “Code” tab of your function details. Choose AWSSDKPandas-Python39 v5 which sources from AWS layer.
Finally, add the codes for get_sensor_bmp280 and post_sensor_bmp280 to their respective functions.
# get_sensor_bmp280
import pymysql
# rds settings
rds_host = "sensor-bmp280.c1hychjmjdhi.ap-southeast-2.rds.amazonaws.com"
username = "admin"
password = "<your_password>"
db_name = "sensor_bmp280"
connection = pymysql.connect(host=rds_host, user=username, passwd=password, db=db_name)
def lambda_handler(event, context):
cursor = connection.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS bmp280 (id INTEGER NOT NULL AUTO_INCREMENT, temperature FLOAT NOT NULL, pressure FLOAT NOT NULL, altitude FLOAT NOT NULL, timestamp DATETIME NOT NULL, PRIMARY KEY (id));")
cursor.execute("SELECT * from bmp280;")
ret = []
for i in list(cursor.fetchall()):
ret.append({
"id": i[0],
"temperature": i[1],
"pressure": i[2],
"altitude": i[3],
"timestamp": i[4].strftime("%Y-%m-%d %H:%M:%S")})
return ret
# post_sensor_bmp280
import pymysql
import datetime
# rds settings
rds_host = "sensor-bmp280.c1hychjmjdhi.ap-southeast-2.rds.amazonaws.com"
username = "admin"
password = "<your_password>"
db_name = "sensor_bmp280"
connection = pymysql.connect(host=rds_host, user=username, passwd=password, db=db_name)
def lambda_handler(event, context):
cursor = connection.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS bmp280 (id INTEGER NOT NULL AUTO_INCREMENT, temperature FLOAT NOT NULL, pressure FLOAT NOT NULL, altitude FLOAT NOT NULL, timestamp DATETIME NOT NULL, PRIMARY KEY (id));")
cursor.execute("SELECT COUNT(*) FROM bmp280;")
least_id = cursor.fetchone()[0]
timestamp = (datetime.datetime.now() + datetime.timedelta(hours=7)).strftime("%Y-%m-%d %H:%M:%S")
new_value = f"{event['temperature']}, {event['pressure']}, {event['altitude']}, \"{timestamp}\""
cursor.execute(f"INSERT INTO bmp280 (temperature, pressure, altitude, timestamp) VALUES ({new_value});")
connection.commit()
return f"Success added ({least_id + 1}, {new_value})"
IAM (Identity and Access Management)
Link: https://us-east-1.console.aws.amazon.com/iamv2/home#/policies
In order to enable your Lambda to access and modify the network interface, it is necessary to create a policy that includes the specific permissions needed. These permissions include DescribeInstances, CreateNetworkInterface, AttachNetworkInterface, DescribeNetworkInterfaces, and DeleteNetworkInterface. However, instead of specifying only these permissions, the policy shown in the image grants full access to the Lambda. This is done to simplify the process and avoid potential issues with restricted access.
Once you have created the policy, open it and click on the “Policy usage” menu. Then, attach permissions to both of the Lambda functions’ roles.
API Gateway
Link: https://ap-southeast-2.console.aws.amazon.com/apigateway/main/apis?region=ap-southeast-2
Next, you’ll need to create a REST API named Embedded System.
Create a resource named bmp280 and create GET and POST methods inside it.
Finally, assign the functions you created, get_sensor_bmp280 and post_sensor_bmp280, to the GET and POST methods, respectively.
Once you have done this, deploy your API. You can name the stage anything you like.
Open your API Gateway Dashboard, and your API URL will be shown (mine is https://chznne1yi9.execute-api.ap-southeast-2.amazonaws.com/prod/). Don’t forget to add a /bmp280 path after the URL to access the resource.
Congratulations! You have successfully created a REST API using various AWS services such as EC2, RDS, Lambda, and API Gateway. This API can handle GET and POST requests, which allow you to store and access data in a MySQL database. With the GET request, you can retrieve specific data from the database, while the POST request enables you to add new data to the database. If you have any questions, feel free to reach out to me. See you!
(*) Trivia:
- You can also display the bmp280 table directly from your EC2 instance.