Hello everyone, I am so happy to introduce you today the coolest way to create an endpoint!
Whatever you want to save files or data in a Database, this post will show you how to easily make a Restful API quickly and why not a full project. But first, let’s introduce you some important points to begin.
You need to setup your environment
You need to create an AWS account
Deploying a Lambda in AWS without an account is impossible. However, it’s free and easy like any website on the Internet. Just go to aws.amazon.com and create a new account. Don’t forget to secure your root user with 2FA! And protect it with a strong password.
You have to create a Programmable User
A programmable user is a user like that connects to AWS with your account. It represents your computer and maybe an application like a website or a mobile app. It’s based on limited access that you give to this user. So, be careful. Don’t add a full access to administrate your account.
In our case, it’s necessary to run CLI commands to our computer, that’s why you have to install AWS CLI.
You should install some dependencies
Now, your computer is able to connect to AWS via CLI. Then you need to install SAM (Serverless Application Model), This tool will provide a command line tool to initiate, build and deploy the RESTFul Api (Lambda). But, you need to install Docker to be able to run on local. Simply, Docker must be installed in all developers’s computer, right?
Generate a Lambda Function
The RESTFull API in AWS is a stack. SAM will create a template that creates all necessary resources to create the endpoint. Technically, the RESTFull Application is:
- An API Gateway with secured URL
- Lambda Function that will contain the logic (FastAPI Application)
- S3/DynamoDB/SQS… All AWS resources that Applications needs
- Roles, Policies that allow your Lambda for access to different resources
This stack is presented by only one file named template.yaml. It’s a Yaml file that list all these resources adding configurations.
Our first template
In our example, we will create an endpoint that saves posted data in DynamoDB (Database), This RESTFul API will be named MyStoreAPI. So, let’s bootstrap a lambda template with the command bellow.
sam init
Sam init
is the command that initiates a lambda project with a very helpful questions like this.
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
Let’s chose the first option to have a quick starter template.
There is two ways to deploy a lambda function, by pushing a zip file containing all packages and codes in it and publishing a Docker image in the official repository Amazon ECR. In this case, we will chose the zip package.
What package type would you like to use?
1 - Zip (artifact is a zip uploaded to S3)
2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1
Then, we should select the runtime
Which runtime would you like to use?
1 - nodejs14.x
2 - python3.9
3 - ruby2.7
4 - go1.x
5 - java11
6 - dotnetcore3.1
7 - nodejs12.x
8 - nodejs10.x
9 - python3.8
10 - python3.7
11 - python3.6
12 - python2.7
13 - ruby2.5
14 - java8.al2
15 - java8
16 - dotnetcore2.1
Runtime: 2
This is a list of all Run-times we can chose. But, If you want a custom runtime you can make your custom Docker image. In our case we will select Python3.9.
After few seconds, SAM will download files, configure and create a full project for us:
We have to update the code
Before starting coding the endpoint there is some code updates to do. First, let’s rename hello_world to src/ because It’s the folder that contains the source code. Then , rename everything related to hello_world
to src
in template.yaml
in CodeUri: hello_world/
, the function name, and the README.md
file. Also you need to update the API Gateway’s configuration by edition the same file to this code:
Events:
Root:
Type: Api
Properties:
Path: /
Method: ANY
NonRoot:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
This method will accept all verbs (GET, POST, PUT, DELETE) to roots and other routes and will configure the API Gateway to accept all the requests.
Under the Function name in template.yaml
we have to add these lines:
Properties:
Policies:
- DynamoDBCrudPolicy:
TableName: MyStoreDb # need to be created
- S3CrudPolicy:
BucketName: !Ref MyStoreS3Bucket
# To add a bucket releated to this project add this lines
# MyStoreS3Bucket:
# Type: AWS::S3::Bucket
These lines will add policies to have access to CRUD DynamoDB and an S3 Bucket.
✍️ Let’s start coding the main Endpoint
Great! Now we are ready to start coding the RESTFul endoint. So, let’s update requirements.txt
to put FastAPI and other packages we need.
requests # to get a http client
boto3 # This package helps us to use AWS services
fastapi # The FastAPI official package
mangum # This will run FastAPI server as a function
pydantic # Data validation and settings management
Now we are ready to write a Python API and here some example to get started with FastAPI!
This is app.py
file:
import os
from fastapi import FastAPI
from mangum import Mangum
from starlette.datastructures import CommaSeparatedStrings
import os
from routes import router
ALLOWED_HOSTS = CommaSeparatedStrings(os.getenv("ALLOWED_HOSTS", ""))
API_VERSION_PATH = "/api/v1"
PROJECT_NAME = "My Store API"
stage = os.environ.get('STAGE', None)
root_path = f"/{stage}" if stage else "/"
description = """
my Store API 🚀
"""
app = FastAPI(
title=PROJECT_NAME,
description=description,
root_path=root_path,
version="0.0.1"
)
app.include_router(router, prefix=API_VERSION_PATH )
handler = Mangum(app)
And this is routes.py
file
from fastapi import APIRouter, HTTPException
from starlette.requests import Request
import json
router = APIRouter()
# This is an example but may be used as a health check
@router.get("/status", description="This is a health check", tags=["Health Check"])
def get_status():
# Create a client.
return {"status": "OK"}
As we can see in app.py
file, handler = Mangum(app)
. This means that AWS Lambda needs to run handler
function to invoke all the API. That’s why, in template.yaml we should specify this in this line Handler: app.handler
(file_name.function_name)
We are ready to deploy the function and continue coding the Endpoint. For more code examples, go check my other posts about python and lambda like this post Files in S3 AWS Python Lambda, how to handle them?
☁️ Deploy the Lambda Function
To deploy the Lambda we only need to run sam deploy --guided
and follow the guide.
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Found
Reading default arguments : Success
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]:
AWS Region [eu-west-3]:
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [Y/n]: Y
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: Y
DocusignApiFunction may not have authorization defined, Is this okay? [y/N]: y
DocusignApiFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
This will create the samconfig.toml
file that will be used later without –guided option, most importantly, SAM will deploy the CloudFormation stack by creating the API Gateway, the Lambda function, roles and policies and all resources from the template.yaml
on this stack.
This stack can be delete with one command and can be updated by adding more resources so pay attention by having a meaningful name of the stack.
Update the API Gateway
After deploying the stack, the API Gateway will create two stages (Prod and Stage) that we need to update in the console by deleting them first, then, create a new one with a given name dev
Congraculation! you endpoint is live in this link https://{APIGW-ID}.execute-api.{REGION}.amazonaws.com/dev 👏
Helpful commands to manage your lambda
I create a Makefile
that includes all commands I want to run. Then, I can only type make logs
to show logs in real time or make remove
to destroy and clean the stack. You have to clean the stack after developing because the API Gateway is public.
REGION= the AWS Region
STACK_NAME= the stack name
LAMBDA= The Lambda Function name from template.yaml
build:
sam build --use-container
logs:
sam logs -n ${LAMBDA} --stack-name ${STACK_NAME} --tail
test:
python -m pytest tests -v
local:
sam build --use-container
sam local start-api
remove:
aws cloudformation delete-stack --stack-name ${STACK_NAME}
describe:
aws cloudformation describe-stack-resources --stack-name ${STACK_NAME}
If you have any question or comment, please comment on this Post.
If you want to hash a file in a Lambda check this post https://kaliex.co/how-to-hash-a-file-in-a-bucket-s3-using-aws-lambda/
1 Comment