This is a demo project that deploys a FastAPI application to AWS Lambda using AWS SAM.
The frontend of the application is a Vue 3 single-page application that is served from the root path of the FastAPI backend.
The backend also includes Powertools for AWS Lambda for enhanced logging and tracing in AWS.
Poetry is used for Python dependency management.
You can view the live version at:
https://3digtt1sjd.execute-api.eu-central-1.amazonaws.com/Prod/docs.
The SAM CLI builds and packages the app from the contents of the /src
directory as specified in template.yaml
in the project root.
The /src
directory contains the FastAPI app in /src/app
and a requirements.txt
file that specifies the Python runtime dependencies.
Since the frontend is served from FastAPI, frontend build artifacts are generated in /src/frontend
in order to be included in the SAM build.
The /frontend
folder contains the Vue 3 frontend as a self-contained project created with npm create vue@latest
.
/frontend # Vue 3 frontend
/src
/app
main.py # FastAPI app
/frontend # frontend build artifacts
requirements.txt # Python dependencies
/tests
The frontend is a Vite-powered Vue 3 single-page application.
The build
npm script in /frontend/package.json
is configured to output the build artifacts to /src/frontend
so that they can be included in the SAM build.
You can run the frontend build manually with:
cd frontend
npm run build
The frontend is served from the root path of the FastAPI app.
This runtime integration is implemented in /src/app/frontend.py
:
def mount_frontend(app: FastAPI, build_dir: Path, assets_folder="assets") -> FastAPI:
"""Serves a frontend application at the root path `/`
Args:
app: FastAPI application instance
build_dir: Frontend build directory
(generated by `yarn build` or `npm run build`)
Returns:
FastAPI: instance with the frontend application mounted
"""
app.mount(
f"/{assets_folder}/",
StaticFiles(directory=(build_dir / assets_folder), html=True),
name="assets",
)
templates = Jinja2Templates(directory=build_dir)
@app.get("/{_full_path:path}", include_in_schema=False)
async def serve_frontend(request: Request, _full_path: str) -> HTMLResponse:
return templates.TemplateResponse("index.html", {"request": request})
return app
Therein, the index.html
file is served from the root path /
as a Jinja2Templates.TemplateResponse
and the frontend build assets are statically mounted at /assets/
using FastAPI/Starlette's StaticFiles
class.
The approach is taken from this answer on StackOverflow: https://stackoverflow.com/a/70065066/733291.
This project uses Poetry for dependency management.
Poetry organize dependencies in groups and this project distinguishes following groups:
main
- dependencies for the FastAPI appdev
- dependencies specifically for developmenttest
- dependencies for running tests with pytestcode-qa
- dependencies for code quality checks
The main
group is the only one that is needed for the deployed app.
Therefore, the requirements.txt
file in the /src
directory is a direct dependency of the poetry.lock
file.
As such, it is generated from the poetry.lock
file with only dependencies from the main
group using the poetry export
command.
This happens automatically as part of pre-commit hooks (see /pre-commit-config.yaml
).
You can update it manually with:
poetry export -f requirements.txt --only main --output src/requirements.txt --without-hashes
During development, you can run the frontend build and the backend concurrently in separate processes.
Start the frontend build in watch mode:
cd frontend
npm install
# runs the frontend build with --watch flag
npm run watch
Start the FastAPI app in dev mode using uvicorn:
poetry install
cd src
python -m app.main
You can manually deploy the app to AWS using the AWS SAM CLI.
sam build --use-container
sam deploy --guided
You can also deploy the app from a GitHub Actions workflow to AWS.
sam pipeline init --bootstrap
This command will initiate an interactive assistant that guides you through creating the necessary AWS infrastructure resources.