Serverless AWS Lambda ➕ DynamoDB ➕ FastAPI ➕ Github Actions
Table of Contents 📚
- Introduction
- AWS Serverless Application Model (AWS SAM)
- Creating Function
- Adding Dependencies
- Writing APIs using FastAPI
- Creating Handler using Mangum
- Updating Cloudformation Template
- Build & Deploy
- Conclusion
Introduction
In the Part 1 of this blog, we will go through the steps of setting up AWS SAM, creating a Lambda, and adding FastAPI API endpoints.
You might have heard a lot about serverless functions and their advantages so in this blog we won't be going into the explanation of, what are serverless functions? or where and when to use them?.
In short, a serverless architecture or serverless function can be use when one just wants to focus on the application building part and doesn't want to get into the complexities of setting and configuring a server.
In more layman's terms, a serverless architecture can be compared to Service Apartments/Paying Guests in the real world. When people want a place which is safe, has all the basic necessities, has multiple accomodation options, and provides freedom to add some customisations they look for Service Apartments/Paying Guests. Similarly, in case of application development, if you don't want to deal with setting up servers, securing and configuring them, then serverless is the best option.
AWS Serverless Application Model (AWS SAM)
There are many ways you can create a serverless Lambda function on AWS. A Docker container with an lambda_handler pushed to AWS ECR can be used with Lambda.
Or, zipping the requirements and uploading those to AWS S3 and then building a Lambda function via the console can also work.
But AWS SAM is the best approach to have continuous integration and deployment. AWS SAM provides template specification to define serverless application and a CLI (command line interface) tool to build and deploy.
Moreover, we can integrate Github Actions using with AWS SAM and have a continuous development and deployment pipeline
Requirements
To follow along with this blog you need to install and configure the following
Creating Function
- Open a new VS Code editor window and based on your operating system use cmd + shift + p or ctrl + shift + p and search for "AWS: Create Lambda SAM Application" and select it
- Select Python3.7 or any python version you want
- Select AWS SAM Hello World as the application template
- Name your application and save it inside a folder and export the folder to VS Code
Once the folder is added to the current workspace the structure will look similar to the one in the image below
Adding Dependencies
To create APIs or endpoints using FastAPI we first need to add the fastapi inside the requirements.txt file
requests
fastapi
Writing APIs using FastAPI
Let's create some endpoints. Open the app.py file and comment out the lambda_handler function and create some endpoints as below
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World", "ok": True}
@app.get("/hello")
def hello_mount():
return {"message": "All is well", "ok": True}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q, "ok": True}
Creating Handler using Mangum
Now to handle the function invocation or various events via the API Gateway or the Load Balancer we use Mangum.
Mangum supports ASGI application frameworks like Starlette, FastAPI, and Quart. To know more about Mangum you can visit this page
Add mangum to our requirements.txt
requests
fastapi
mangum
Now let's create the lambda_handler inside the app.py file
from fastapi import FastAPI
from mangum import Mangum
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World", "ok": True}
@app.get("/hello")
def hello_mount():
return {"message": "All is well", "ok": True}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q, "ok": True}
lambda_handler = Mangum(app = app, lifespan="off")
Updating Cloudformation Template
We need to allow access to all the endpoints we have created above or else we might get 500 error code in response.
To do this add open the template.yaml file and replace the content under Events with the following
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /{proxy+}
Method: any
Http:
Type: Api
Properties:
Path: "/"
Method: Any
After this update, the template file should look something like below
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
hello-world-lambda-python3.7
Sample SAM Template for hello-world-lambda-python3.7
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.7
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /{proxy+}
Method: any
Http:
Type: Api
Properties:
Path: "/"
Method: any
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn
Build & Deploy
Let's build the function and deploy it. To build the function open the terminal and move into the application_name.
Note: application_name refers to the name of the application you gave at the start.
Run the following commands
- Build the application
sam build
Once the build process is complete you will see .aws-sam folder inside your function. This function contains all the packages and files which will be required to run the application
- Deploy the Application
sam deploy --region <region_name> \
--stack-name <name-the-deployment-stack> \
--resolve-s3 --capabilities CAPABILITY_IAM
Let's say we want to deploy it to the us-east-2 region and we name the cloudformation stack as lambda-fastapi-deploy our command will be
sam deploy --region us-east-2 \
--stack-name lambda-fastapi-deploy \
--resolve-s3 --capabilities CAPABILITY_IAM
Once Cloudformation finishes deploying the application to Lambda it will output the endpoint to access all the APIs in the terminal window.
Conclusion
This blog was more of a discovery and setup kind wherein we went through the process of creating APIs using FastAPI and wrapping it into an adapter called Mangum and then deploying it as a Lambda using the Cloudformation template.
In the next part, we will create a few tables inside DynamoDB and try to access them using the Lambda function we created here