Skip to main content

FastAPI Serverless Deployment

In this tutorial, you'll learn how to deploy FastAPI applications in a serverless environment. Serverless architecture allows you to build and run applications without managing server infrastructure, which can reduce operational costs and improve scalability.

Introduction to Serverless Computing

Serverless computing is a cloud execution model where the cloud provider dynamically allocates resources to run your code. You're charged only for the actual compute time consumed, rather than paying for idle servers.

Key benefits of serverless deployments:

  • Cost efficiency: Pay only for what you use
  • Automatic scaling: Handles varying workloads automatically
  • Reduced operational overhead: No server management required
  • High availability: Built-in redundancy and fault tolerance

FastAPI and Serverless: A Perfect Match

FastAPI's lightweight nature and async support make it an excellent choice for serverless environments where cold start times and efficient resource usage are critical. Let's explore how to deploy FastAPI applications in popular serverless platforms.

Deploying FastAPI on AWS Lambda with Mangum

Mangum is an adapter that allows ASGI applications (like FastAPI) to run on AWS Lambda with API Gateway.

Step 1: Set up your project

First, create a new directory and initialize your FastAPI project:

bash
mkdir fastapi-serverless
cd fastapi-serverless
pip install fastapi mangum uvicorn boto3 aws-cli

Step 2: Create your FastAPI application

Create a file named main.py:

python
from fastapi import FastAPI
from mangum import Mangum

# Initialize FastAPI application
app = FastAPI(title="Serverless FastAPI")

@app.get("/")
async def root():
return {"message": "Hello from Serverless FastAPI!"}

@app.get("/items/{item_id}")
async def get_item(item_id: int):
return {"item_id": item_id, "name": f"Sample Item {item_id}"}

# Create Mangum handler for AWS Lambda
handler = Mangum(app)

The key component here is the handler = Mangum(app) line, which wraps your FastAPI app with Mangum to handle AWS Lambda events.

Step 3: Create deployment package

AWS Lambda requires your code and dependencies to be packaged together. Let's create the necessary files:

First, create a requirements.txt file:

fastapi==0.95.0
mangum==0.17.0

Next, create a serverless.yml file for the Serverless Framework (a popular tool for deploying serverless applications):

yaml
service: fastapi-serverless

provider:
name: aws
runtime: python3.9
region: us-east-1
memorySize: 256
timeout: 30

functions:
api:
handler: main.handler
events:
- httpApi:
path: /{proxy+}
method: any

Step 4: Deploy with Serverless Framework

If you haven't installed the Serverless Framework, install it globally:

bash
npm install -g serverless

Then deploy your application:

bash
serverless deploy

After successful deployment, you'll receive an endpoint URL that you can use to access your FastAPI application.

Output example:

Service Information
service: fastapi-serverless
stage: dev
region: us-east-1
stack: fastapi-serverless-dev
api keys:
None
endpoints:
https://abc123def456.execute-api.us-east-1.amazonaws.com/
functions:
api: fastapi-serverless-dev-api

Deploying FastAPI on Azure Functions

Azure Functions is Microsoft's serverless computing service. Let's see how to deploy FastAPI on it.

Step 1: Set up your project

First, install the necessary packages:

bash
pip install fastapi azure-functions

Step 2: Create your FastAPI application

Create a file named __init__.py:

python
import azure.functions as func
from fastapi import FastAPI
from fastapi.middleware.wsgi import WSGIMiddleware
import uvicorn

app = FastAPI(title="FastAPI on Azure Functions")

@app.get("/")
async def root():
return {"message": "Hello from FastAPI on Azure Functions!"}

@app.get("/api/items/{item_id}")
async def get_item(item_id: int):
return {"item_id": item_id, "name": f"Azure Item {item_id}"}

# Azure Functions entry point
async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
return await func.AsgiMiddleware(app).handle_async(req, context)

Step 3: Create Function configuration

Create a function.json file:

json
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post",
"put",
"delete"
],
"route": "{*route}"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}

Step 4: Deploy to Azure Functions

Install the Azure Functions Core Tools:

bash
npm install -g azure-functions-core-tools@3

Initialize and deploy your function app:

bash
func init . --python
func azure functionapp publish your-function-app-name

Real-world Example: Serverless API for a Todo Application

Let's build a more comprehensive example: a serverless API for a todo application using FastAPI and AWS Lambda with DynamoDB.

Step 1: Set up the project

bash
mkdir todo-serverless
cd todo-serverless
pip install fastapi mangum boto3 pydantic

Step 2: Create the FastAPI application

Create a file named main.py:

python
from fastapi import FastAPI, HTTPException
from mangum import Mangum
from pydantic import BaseModel
import uuid
import boto3
from typing import List, Optional

# Initialize FastAPI app
app = FastAPI(title="Todo API Serverless")

# Initialize DynamoDB client
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Todos')

# Pydantic models
class TodoCreate(BaseModel):
title: str
description: Optional[str] = None
completed: bool = False

class Todo(BaseModel):
id: str
title: str
description: Optional[str] = None
completed: bool = False

# API routes
@app.get("/")
async def root():
return {"message": "Todo API Running"}

@app.post("/todos/", response_model=Todo)
async def create_todo(todo: TodoCreate):
todo_id = str(uuid.uuid4())
item = {
'id': todo_id,
'title': todo.title,
'description': todo.description,
'completed': todo.completed
}

table.put_item(Item=item)
return item

@app.get("/todos/", response_model=List[Todo])
async def list_todos():
response = table.scan()
return response.get('Items', [])

@app.get("/todos/{todo_id}", response_model=Todo)
async def get_todo(todo_id: str):
response = table.get_item(Key={'id': todo_id})
if 'Item' not in response:
raise HTTPException(status_code=404, detail="Todo not found")
return response['Item']

@app.put("/todos/{todo_id}", response_model=Todo)
async def update_todo(todo_id: str, todo: TodoCreate):
# Check if todo exists
response = table.get_item(Key={'id': todo_id})
if 'Item' not in response:
raise HTTPException(status_code=404, detail="Todo not found")

# Update todo
table.update_item(
Key={'id': todo_id},
UpdateExpression="set title=:t, description=:d, completed=:c",
ExpressionAttributeValues={
':t': todo.title,
':d': todo.description,
':c': todo.completed
}
)

# Return updated todo
return {
'id': todo_id,
'title': todo.title,
'description': todo.description,
'completed': todo.completed
}

@app.delete("/todos/{todo_id}")
async def delete_todo(todo_id: str):
# Check if todo exists
response = table.get_item(Key={'id': todo_id})
if 'Item' not in response:
raise HTTPException(status_code=404, detail="Todo not found")

# Delete todo
table.delete_item(Key={'id': todo_id})
return {"message": "Todo deleted"}

# Create handler for AWS Lambda
handler = Mangum(app)

Step 3: Create IAM permissions and DynamoDB table

Before deploying, you need to create a DynamoDB table and configure proper IAM permissions. Here's a serverless.yml file that handles this:

yaml
service: todo-api-serverless

provider:
name: aws
runtime: python3.9
region: us-east-1
memorySize: 256
timeout: 30
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: !GetAtt TodosTable.Arn

functions:
api:
handler: main.handler
events:
- httpApi:
path: /{proxy+}
method: any

resources:
Resources:
TodosTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: Todos
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH

Step 4: Deploy the application

bash
serverless deploy

Once deployed, you can interact with your Todo API using the provided endpoint. For example:

Creating a new Todo:

bash
curl -X POST https://your-api-url/todos/ \
-H "Content-Type: application/json" \
-d '{"title": "Learn Serverless", "description": "Deploy FastAPI to serverless"}'

Expected response:

json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Learn Serverless",
"description": "Deploy FastAPI to serverless",
"completed": false
}

Performance Considerations for Serverless FastAPI

When deploying FastAPI in a serverless environment, keep these performance considerations in mind:

Cold Starts

Serverless functions that haven't been used recently experience "cold starts" - a delay when new instances are initialized. To minimize cold start times:

  1. Keep dependencies minimal
  2. Use smaller packages when possible
  3. Consider using provisioned concurrency (AWS) or premium plans (Azure)

Connection Pooling

In serverless environments, database connections should be managed carefully:

python
# Bad practice (creates new connections on each invocation)
def get_db_connection():
return database.connect()

# Better practice (reuse connections across invocations)
db_connection = None

def get_db_connection():
global db_connection
if db_connection is None:
db_connection = database.connect()
return db_connection

Memory Usage

Serverless functions often have memory limits. Monitor your application's memory usage and optimize where necessary.

Summary

In this tutorial, you've learned:

  • How to deploy FastAPI applications to serverless environments
  • Setting up FastAPI with AWS Lambda using Mangum
  • Deploying FastAPI on Azure Functions
  • Building a real-world serverless API with FastAPI and DynamoDB
  • Performance considerations for serverless deployments

Serverless deployment for FastAPI applications offers significant advantages in terms of cost, scalability, and reduced operational overhead. While there are some considerations like cold starts to be aware of, the benefits often outweigh these concerns for many applications.

Additional Resources

  1. AWS Lambda Developer Guide
  2. Azure Functions Documentation
  3. Mangum GitHub Repository
  4. Serverless Framework Documentation
  5. FastAPI Documentation

Exercises

  1. Modify the Todo API to include a due date field and implement filtering todos by their completion status.
  2. Deploy the FastAPI application to Google Cloud Functions (another serverless provider).
  3. Implement authentication for your serverless API using JWT tokens.
  4. Create a simple frontend application that interacts with your serverless FastAPI backend.
  5. Optimize the cold start performance of your FastAPI serverless application and measure the improvements.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)