How to deploy FastAPI app using AWS CDK Typescript
Tags: python, fastapi, serverless, cdk
Published: 2023-06-14 06:13:20

## **Introduction**
In this post, I will explain how to deploy FastAPI to a Lambda function, using the Typescript-based AWS CDK.

## **Prerequisite**
This article is intended for those who have experience building Lambda functions and API Gateways with Typescript-based AWS CDK.

- Setup of AWS CDK and AWS CLI is omitted.
- Python setup is omitted.
- FastAPI description is omitted.


Development Environment
- node v18.5.0
- CDK 2.83.1
- Python 3.11.3

Install the following
```
pip install fastapi
pip install mangum
pip install uvicorn
```

---

## **Create the app**

```
mkdir sample-ts-fastapi
cd sample-ts-fastapi
cdk init --language typescript
npm install @aws-cdk/aws-lambda-python-alpha
```
Reference
[@aws-cdk/aws-lambda-python-alpha](https://www.npmjs.com/package/@aws-cdk/aws-lambda-python-alpha)

## **Defining Lambda and API Gateway**
Modify `lib/sample-ts-fastapi-stack.tsas` follows.

```
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";

import { PythonFunction } from "@aws-cdk/aws-lambda-python-alpha";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { LambdaRestApi } from "aws-cdk-lib/aws-apigateway";

export class SampleTsPyFastapiStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const apiName = `SampleApi`;
    const lambdaName = `MyLambda`;

    const lambda = new PythonFunction(this, lambdaName, {
      entry: "lambda",
      runtime: Runtime.PYTHON_3_10,
      index: "main.py",
      handler: "handler",
      environment: {},
    });
    const api = new LambdaRestApi(this, apiName, {
      handler: lambda,
    });
  }
}
```

## **Create Lambda Function**
The directory and file structure should be as follows.
Create main.py and user.py.

```
lambda/
 ├ main.py
 ├ router/
   └ user.py
```

main.py

```
from fastapi import FastAPI
from mangum import Mangum
from .routers import user

app = FastAPI()


@app.get("/", tags=["root"])
async def root():
    return {"message": "Hello World"}

app.include_router(user.router)

handler = Mangum(app, lifespan="off")
```

user.py

```
from fastapi import APIRouter


router = APIRouter()

@router.get("/user", tags=["user"])
async def getUser():
    return {"message": "test user"}
```

Let’s try to run it in this state.

```
uvicorn lambda.main:app --reload
```

The API created on this page is now displayed. `http://127.0.0.1:8000/docs`

## **Deploy**

- Modify `from routers import user` in main.py. (It did not pass at `.routers`.)
- Launch Docker in advance

```
cdk deploy
```

## **Adding the lambda layer**
Since we are using FastAPI and Mangum, we create and add two layer.
There is also a way to include the Lambda Layer with the CDK and deploy it, but this time we did it by creating it separately.

1. Create s3 bucket
2. Zip the Python library
3. Upload zip to s3
4. Copy its Object URL
5. Create layers from the lambda page (Object URL is required)
6. Once the layer is created, copy its ARN

For 2 and 3, for example, create it this way.

```
pip install -t python/ fastapi
zip -r layer1.zip python
aws s3 cp layer1.zip s3://{backet name}/layer1.zip
```

Now that we have created two layers, FastAPI and Mangum, we can add them to the lambda function described earlier.

From the Lambda page of the AWS console, go to the function details page and add two layers. Enter the ARN from earlier here.

This completes the setup.

---

## **Conclusion**
That’s it, I was able to get Python’s FastAPI to work with Lambda on the Typescript-based AWS CDK.

However, I could not figure out why the import path in the main.py code would not pass in Lambda unless I did it this way.

I am a beginner in Python. If there is a way to write code that can be executed without worrying about the difference between the path environment on Lambda and the local path environment, I would appreciate it if someone could tell me.