https://github.com/iwstkhr/aws-lambda-web-adapter-fastapi-example
Example of FastAPI using Lambda Web Adapter
https://github.com/iwstkhr/aws-lambda-web-adapter-fastapi-example
aws lambda lambda-web-adapter
Last synced: about 1 year ago
JSON representation
Example of FastAPI using Lambda Web Adapter
- Host: GitHub
- URL: https://github.com/iwstkhr/aws-lambda-web-adapter-fastapi-example
- Owner: iwstkhr
- License: mit
- Created: 2024-08-11T15:10:32.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-21T22:06:28.000Z (about 1 year ago)
- Last Synced: 2025-02-23T20:42:15.383Z (about 1 year ago)
- Topics: aws, lambda, lambda-web-adapter
- Language: TypeScript
- Homepage:
- Size: 116 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## Introduction
[Lambda Web Adapter](https://github.com/awslabs/aws-lambda-web-adapter) has revolutionized application development on AWS Lambda. It allows developers to build backend services using Docker, a tool familiar to most developers.
This repository guides you through the process of developing API backends with [FastAPI](https://fastapi.tiangolo.com/) using Lambda Web Adapter.
## Overview
### Traditional Design
The traditional AWS design using API Gateway and multiple Lambda functions can become unwieldy when managing many APIs:

### Design Using Lambda Web Adapter
Lambda Web Adapter simplifies the architecture, requiring only a single API Gateway route and one Lambda function:

## Getting Started
### Bootstrapping AWS CDK Environment
First, bootstrap your AWS CDK environment.
> [!NOTE]
> You can skip this step if you've already done it.
Follow the [AWS CDK guide](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_install) to install AWS CDK locally:
```shell
npm i -D aws-cdk
npx cdk bootstrap aws:///
```
### Initializing a CDK Project
To initialize your CDK project, run the following command:
```shell
mkdir cdk && cd cdk
npx cdk init app --language typescript
```
### Setting up FastAPI
Install FastAPI with the following commands:
```shell
python -m venv .venv
source .venv/bin/activate
pip install "fastapi[standard]"
mkdir src
pip freeze > ./src/requirements.txt
```
## Backend API using FastAPI
### Writing an API
Here's an example FastAPI application saved to `./src/main.py`:
```python
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
### Testing the API
Start the FastAPI server with:
```shell
fastapi dev ./src/main.py
```
Test the API with your preferred tool:
```shell
curl "http://127.0.0.1:8000/"
{"Hello":"World"}
curl "http://127.0.0.1:8000/items/1?q=keyword"
{"item_id":1,"q":"keyword"}
```
## Containerizing using Docker
### Dockerfile
To containerize the FastAPI backend, write the following code and save it to `./docker/Dockerfile`. This Dockerfile is designed to handle both development and production environments effectively.
**Key points:**
- **Base Image**: We use [`public.ecr.aws/docker/library/python:3.12-alpine`](https://gallery.ecr.aws/docker/library/python) as our lightweight and secure base image (line 2).
- **Lambda Web Adapter**: The Lambda Web Adapter is added for seamless AWS Lambda integration (line 22).
- **Port Configuration**: The backend listens on **port 8080** by default for production to match the Lambda Web Adapter's expected configuration (line 25).
For more details on Lambda Web Adapter usage, refer to its [official documentation](https://github.com/awslabs/aws-lambda-web-adapter?tab=readme-ov-file#usage).
```dockerfile line="2,22,25"
# Base image: Python 3.12 Alpine
FROM public.ecr.aws/docker/library/python:3.12-alpine AS base
ENV APP_ROOT=/code
# Copy requirements and install dependencies
COPY ./src/requirements.txt $APP_ROOT/
RUN pip install --no-cache-dir --upgrade -r $APP_ROOT/requirements.txt
# Development stage
FROM base AS dev
ENV ENV=dev
EXPOSE 8000
CMD ["sh", "-c", "fastapi run $APP_ROOT/main.py --port 8000"]
# Production stage
FROM base
ENV ENV=prod
EXPOSE 8080
COPY ./src $APP_ROOT
# Copy Lambda Web Adapter
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter
# Run FastAPI backend on port 8080 for Lambda Web Adapter
CMD ["sh", "-c", "fastapi run $APP_ROOT/main.py --port 8080"]
```
In the next step, we will set up Docker Compose to streamline local development and testing.
### Docker Compose for Local Development
While this repository does not include database usage, in real-world scenarios, you often work with databases such as DynamoDB, MySQL, or others. To facilitate local development and testing, we can set up Docker Compose.
Create a `./docker/compose.yaml` file with the following content:
```yaml
services:
api:
build:
context: ../
dockerfile: ./docker/Dockerfile
target: dev
ports:
- "8000:8000"
volumes:
- ../src:/code
```
#### Key Configuration Details
- **Build Context**: Points to the project root (`../`) and uses the development stage of the Dockerfile (`target: dev`).
- **Ports Mapping**: Maps the container's port `8000` to the host's port `8000` for local access.
- **Volumes**: Mounts the local `src` directory to the container's `/code` directory to enable hot-reloading of code during development.
#### Running the Backend Service
To start the backend service locally using Docker Compose, run the following commands:
```shell
cd docker
docker compose up
```
When the service starts successfully, you should see logs similar to:
```plaintext
api-1 | INFO: Started server process [1]
api-1 | INFO: Waiting for application startup.
api-1 | INFO: Application startup complete.
api-1 | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
```
You can now access the API at `http://127.0.0.1:8000` and test it as usual using tools like `curl`, Postman, or a browser.
Next, we will explore deploying the FastAPI application to AWS Lambda using AWS CDK.
## Deploying to AWS
### Defining AWS Resources using AWS CDK
To deploy the FastAPI backend to AWS, define the necessary resources using AWS CDK. The CDK simplifies resource creation by allowing you to define infrastructure in code.
#### Step 1: Configure the Entry Point
Paste the following code into `cdk/bin/cdk.ts`. This is the entry point for your AWS CDK application.
```typescript
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { CdkStack } from '../lib/cdk-stack';
const app = new cdk.App();
new CdkStack(app, 'App');
```
#### Step 2: Define the Infrastructure Stack
In `cdk/lib/cdk-stack.ts`, define the AWS Lambda function and API Gateway. The following code creates a Dockerized Lambda function and integrates it with an API Gateway REST API.
```typescript line="20,23"
import * as cdk from 'aws-cdk-lib';
import type { Construct } from 'constructs';
import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway';
import {
DockerImageCode,
DockerImageFunction,
LoggingFormat,
} from 'aws-cdk-lib/aws-lambda';
import * as path from 'node:path';
import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
export class CdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Dockerized Lambda Function
const lambda = new DockerImageFunction(this, 'function', {
functionName: 'fast-api-app-function',
loggingFormat: LoggingFormat.JSON,
memorySize: 512, // Larger memory to avoid timeout
code: DockerImageCode.fromImageAsset(path.join(__dirname, '..', '..'), {
file: path.join('docker', 'Dockerfile'),
platform: Platform.LINUX_AMD64, // Required for Apple Silicon users
exclude: ['*', '!src', '!docker'],
}),
});
// API Gateway REST API
new LambdaRestApi(this, 'api', {
handler: lambda,
deploy: true,
});
}
}
```
##### Keynotes
- **Memory Size**: Set `memorySize` to 512 MB or higher (line 20). This prevents potential timeouts caused by insufficient memory.
- **Platform Configuration**: Use `Platform.LINUX_AMD64` (line 23) if you are using Apple Silicon. Without this, you may encounter the error: `Error: fork/exec /opt/extensions/lambda-adapter: exec format error Extension.LaunchError`.
With these files in place, you're ready to deploy your resources.
#### Step 3: Deploy the Resources
Navigate to your CDK project directory and run the following command to deploy:
```shell
cd cdk
npx cdk deploy
```
During deployment, you may be prompted to confirm resource creation. Respond with `y` to proceed:
```plaintext
Do you wish to deploy these changes (y/n)? y
App: deploying... [1/1]
App: creating CloudFormation changeset...
✅ App
✨ Deployment time: 52.67s
Outputs:
App.apiEndpoint9349E63C = https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/
Stack ARN:
arn:aws:cloudformation:::stack/App/
✨ Total time: 55.42s
```
The deployment will output the API Gateway endpoint, which you can use to test your API.
### Testing the App
Test the deployed APIs:
```shell
curl "https:///prod/"
{"Hello":"World"}
curl "https:///prod/items/1?q=keyword"
{"item_id":1,"q":"keyword"}
```
## Conclusion
Lambda Web Adapter significantly simplifies API development on AWS Lambda by reducing complexity and facilitating local testing capabilities. With its ability to streamline AWS architectures, it is an invaluable tool for modern web development.
Happy Coding! 🚀