Deploying a FastAPI backend using AWS Amplify Container-based REST APIs
siegerts
Posted on May 13, 2021
No surprise that it's a difficult process to go from development to production deployments in an organization š¤·.
This is especially true for analytics and data science teams developing models or business logic. There's usually not a clear path or tooling to support application hand-offs or deployments across teams.
One way to bridge the gap between applications is to allow for service-to-service communication. REST APIs are great for this type of use-case. Especially when auto-generated, interactive documentation, is available out-of-the-box š.
AWS Amplify provides a great option for this - Serverless containers using API Gateway + AWS Fargate.
This guide will follow the steps outlined in the Serverless containers section of the Amplify documentation and the FastAPI Docker Deployment documentation to quickly create and deploy a production-ready, scalable REST API.
Prerequisites
You'll need to have the below installed and configured.
-
AWS Amplify CLI - working with Amplify (I'm using
v4.50.2
) - Docker - testing the APIs locally
FastAPI
As mentioned above, we'll use FastAPI as the backend framework. The application pattern will feel natural if you're familiar with Flask.
FastAPI has quickly become a go-to framework for setting up APIs for data science and analytics-based workloads. From the project page:
FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
Among some of the callouts:
Fast: Very high performance, on par with NodeJS and Go
Robust: Get production-ready code. With automatic interactive documentation.
This is a great option for data science teams that want to focus on productionalizing APIs with the ability to scale in the future if needed.
Also, as we'll see below, testing locally is a smooth process using Docker.
Serverless containers with Amplify
If you need an escape hatch from just using Lambda then this may be a great option for you. We'll walk through a more basic set up below but the same approach can be leveraged for more complex backends using a docker-compose.yml configuration.
Serverless containers provide the ability for you to deploy APIs and host websites using AWS Fargate. Customers with existing applications or those who require a lower level of control can bring Docker containers and deploy them into an Amplify project fully integrating with other resources.
Project set up
Okay, let's deploy an API.
First, create a new directory and initialize the the Amplify project. In this example, I'm not hooking up a frontend so I just select the default options. But, if a frontend is something that you're interested in, then it's possible to layer that on and have the UI (React, Vue, etc.) talk to the backend API that is being created.
Make the directory.
mkdir fastapi-amplify
Initialize the Amplify project.
amplify init
Terminal workflow
Scanning for plugins...
Plugin scan successful
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project fastapiamplify
? Enter a name for the environment dev
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using none
? Source Directory Path: src
? Distribution Directory Path: dist
? Build Command: npm run-script build
? Start Command: npm run-script start
Enabling container-based deployments
Now, with the project initialized, we need to enable the use of the container-based deployment options.
amplify configure project
Terminal workflow
? Which setting do you want to configure? Advanced: Container-based deployments
Using default provider awscloudformation
? Do you want to enable container-based deployments? Yes
Adding the API
With the project configured, let's add the soon-to-be API.
amplify add api
Terminal workflow
? Please select from one of the below mentioned services: REST
? Which service would you like to use API Gateway + AWS Fargate (Container-based)
? Provide a friendly name for your resource to be used as a label for this category in the project: fastapirest
? What image would you like to use Custom (bring your own Dockerfile or docker-compose.yml)
? When do you want to build & deploy the Fargate task On every "amplify push" (Fully managed container source)
? Do you want to restrict API access No
Successfully added resource fastapirest locally.
The CLI will output some next steps for setting up the API to use a bring-your-own-container setup.
Next steps:
- Place your Dockerfile, docker-compose.yml and any related container source files in "amplify/backend/api/fastapirest/src"
- Amplify CLI infers many configuration settings from the "docker-compose.yaml" file. Learn more: docs.amplify.aws/cli/usage/containers
- Run "amplify push" to build and deploy your image
Following the above steps, the following app/ and Dockerfile are added to the API directory in the Amplify backend.
.
āāā amplify/backend/api/<api-name>/src/
+ ā āāā app
+ ā āāā main.py
+ āāāāāāā Dockerfile
Adding the Dockerfile
This can be modified based on the needs and requirements of the project but the below default Dockerfile will get you up-and-running immediately with FastAPI.
I've adjusted the example in the FastAPI docs to use python3.8
instead of python3.7
and added the statement to expose port 80.
# Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8
# for Amplify
# https://docs.amplify.aws/cli/usage/containers#deploy-a-single-container
EXPOSE 80
COPY ./app /app
Make sure to add EXPOSE 80
to specify a port to communicate with the container. Amplify will suggest to use port 80 if you don't provide one.
Setting up the API
Now, we can add in the API logic in the main.py file within app/.
# main.py
from typing import Optional
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: Optional[str] = None):
return {"item_id": item_id, "q": q}
Testing locally
With everything in place, we can test the API using Docker. Jump into the backend API directory (i.e. where the Dockerfile
is) and build the image.
cd amplify/backend/api/<api-name>/src/
Build the image.
docker build -t fastapi .
Now, you can run the image locally, exposed on port 80 of your localhost
setup.
docker run -d --name fastapi -p 80:80 fastapi
You'll see the auto-generated API documentation at http://127.0.0.1/redoc or http://127.0.0.1/docs.
Deploying to Amplify š
Awesome! Now let's push this to Amplify.
amplify push
When prompted, select Yes
to Create the new resource.
(š dev) š¶ ā fastapi-amplify amplify push (main) ā
ā Successfully pulled backend environment dev from the cloud.
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | ------------- | --------- | ----------------- |
| Api | fastapirest | Create | awscloudformation |
? Are you sure you want to continue? Yes
After the process is complete. š
ā All resources are updated in the cloud
REST API endpoint: https://<id>.execute-api.<region>.amazonaws.com
Testing the deployed API
After being deployed, the API can be accessed using the endpoint above:
Also, the live API documentation is live at the https://<endpoint>/docs
and https://<endpoint>/redoc
.
/docs
route
/redoc
route
This is just scratching the surface of configuration options. Hope this helps you get running quickly with serverless FastAPI backends!
Subscribe to get my latest content by email -> Newsletter
Posted on May 13, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.