Transform APIs with FastAPI and Lambda: What’s the Secret Recipe for Serverless Success?

Building Serverless APIs with FastAPI: Your Path to Effortless Scalability and Efficiency

Transform APIs with FastAPI and Lambda: What’s the Secret Recipe for Serverless Success?

Deploying serverless FastAPI functions on platforms like AWS Lambda can transform how we build scalable and efficient APIs. It means freeing ourselves from the burdens of managing traditional servers and diving into a world where infrastructure takes care of itself. So, let’s break down the whole process, step by step, from setting up your environment to handling those tricky migrations.

First off, you need to make sure you’ve got the essential tools installed on your local machine. For FastAPI, these are Python, Docker, and the AWS CLI. If any of these aren’t already on your machine, you’ll need to grab them. Here’s the deal:

sudo apt-get update
sudo apt-get install python3 python3-pip
sudo apt-get install docker.io
sudo apt-get install awscli

With those tools ready to roll, the next step is to create your FastAPI application. Below is a simple FastAPI app that serves as the heart of your serverless function.

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/hello/{name}")
def hello(name: str):
    return {"message": f'Hello from FastAPI, {name}'}

In this setup, a requirements.txt file is your go-to for specifying dependencies like fastapi and mangum.

fastapi==0.89.1
mangum==0.17.0

Making your FastAPI app AWS Lambda compliant involves using mangum, which bridges FastAPI with AWS Lambda’s serverless environment.

from fastapi import FastAPI
from mangum import Mangum

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/hello/{name}")
def hello(name: str):
    return {"message": f'Hello from FastAPI, {name}!'}

handler = Mangum(app)

To deploy serverless apps efficiently, the Serverless Framework is a gem. First, install its CLI and configure your AWS credentials.

npm install -g serverless
serverless config credentials --provider aws --key <YOUR_KEY> --secret <YOUR_SECRET_KEY>

The key to deploying is the serverless.yml file, which sets up the service, provider, runtime, and functions.

service: serverless-fastapi
frameworkVersion: '3'
provider:
  name: aws
  runtime: python3.9
  region: eu-west-1
  stage: ${opt:stage, "dev"}
plugins:
  - serverless-python-requirements
custom:
  pythonRequirements:
    dockerizePip: true
functions:
  api:
    handler: app.handler
    events:
      - httpApi: '*'

Once configured, deploying your FastAPI to AWS Lambda is a cinch:

serverless deploy

This command will set up all necessary AWS resources like the Lambda function and API Gateway. Alternatively, if containerized deployments are more your speed, using Docker can offer added security and reproducibility. Start with a Dockerfile.

FROM public.ecr.aws/lambda/python:3.8
COPY . ${LAMBDA_TASK_ROOT}
WORKDIR /app
ARG DEBIAN_FRONTEND=noninteractive
RUN yum update -y
RUN yum install python3-pip git -y
RUN pip3 install fastapi --target "${LAMBDA_TASK_ROOT}"
RUN pip3 install mangum --target "${LAMBDA_TASK_ROOT}"
COPY ./requirements.txt ./requirements.txt
RUN pip install -r ./requirements.txt
CMD ["app.handler"]

Building and pushing this image to Amazon ECR involves a few steps:

docker build -t my-fastapi-app .
aws ecr get-login-password --region <YOUR_REGION> | docker login --username AWS --password-stdin <YOUR_ACCOUNT_ID>.dkr.ecr.<YOUR_REGION>.amazonaws.com
docker tag my-fastapi-app:latest <YOUR_ACCOUNT_ID>.dkr.ecr.<YOUR_REGION>.amazonaws.com/my-fastapi-app:latest
docker push <YOUR_ACCOUNT_ID>.dkr.ecr.<YOUR_REGION>.amazonaws.com/my-fastapi-app:latest

Now, it’s time to create the Lambda function and set up an API Gateway through the AWS Management Console or using AWS CLI commands.

aws lambda create-function --function-name my-fastapi-app --runtime python3.8 --role <YOUR_LAMBDA_EXECUTION_ROLE> --handler app.handler --image-uri <YOUR_ACCOUNT_ID>.dkr.ecr.<YOUR_REGION>.amazonaws.com/my-fastapi-app:latest
aws apigateway create-rest-api --name my-fastapi-app --description 'API for my FastAPI app'
API_ID=$(aws apigateway get-rest-apis --query 'items[?name==`my-fastapi-app`].id' --output text)
aws apigateway put-method --rest-api-id $API_ID --resource-id $(aws apigateway get-resources --rest-api-id $API_ID --query 'items[?path==`/`].id' --output text) --http-method GET --authorization 'NONE'
aws apigateway put-integration --rest-api-id $API_ID --resource-id $(aws.apigateway get-resources --rest-api-id $API_ID --query 'items[?path==`/`].id' --output text) --http-method GET --integration-http-method POST --type LAMBDA --uri arn:aws:apigateway:<YOUR_REGION>:lambda:path/2015-03-31/functions/arn:aws:lambda:<YOUR_REGION>:<YOUR_ACCOUNT_ID>:function:my-fastapi-app/invocations
aws apigateway create-deployment --rest-api-id $API_ID --stage-name prod

Testing out your FastAPI application is straightforward. For API Gateway, you get the API Gateway URL:

API_URL=$(aws apigateway get-rest-apis --query 'items[?name==`my-fastapi-app`].id' --output text)
echo "https://${API_URL}.execute-api.${YOUR_REGION}.amazonaws.com/prod/"

For the Lambda function URL:

aws lambda create-function-url-config --function-name my-fastapi-app --qualifier $LATEST --auth-type NONE
LAMBDA_URL=$(aws lambda get-function-url-config --function-name my-fastapi-app --qualifier $LATEST --query 'FunctionUrl' --output text)
echo $LAMBDA_URL

And voila, you can access your FastAPI app using these URLs.

When it comes to database migrations, AWS Fargate or other managed services might be a better fit compared to Lambda. Lambda’s transient nature can make running migrations a bit challenging.

Deploying your FastAPI app on AWS Lambda is a pretty slick process with the right tools and configurations. Whether using the Serverless Framework or Docker, the end goal is scalable and efficient serverless APIs. Testing is crucial, and never forget to handle migrations and package optimizations for smooth sailing.