Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions server/python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#-------------------------
# Python / FastAPI backend
#-------------------------

# Byte-compiled / optimized files
__pycache__/
*.py[cod]
*$py.class

# Virtual environment
.venv/

# Environment variables
.env

#MacOS files
.DS_Store
123 changes: 123 additions & 0 deletions server/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Welcome to the Python Backend

TOC
1. [Overview](#overview)
2. [Getting Setup](#getting-setup)
3. [Learning FastAPI](#learning-fastapi)
4. [Exploring the Codebase](#exploring-the-codebase)
5. [Feature Parity Status](#feature-parity-status)
6. [Utilities and Nice to Know](#nice-to-know)


## Overview
We're porting our Express backend to Python/FastAPI to achieve **functional parity** - same endpoints, same responses, same MongoDB operations. This allows one frontend to work with multiple backends.


**Important**: We're not rewriting - we're replicating behavior exactly. So this means we are figuring out the pythonic way of doing things. You will find that we can accomplish things with Fast in fewer lines of code than in Express.

## Getting Setup
0. Install Python if you don't already have it. (*Depending on your version of python, you might need to use python3 and pip3 vs python and pip*)
1. Clone from my fork of the main repo.
```sh
https://github.com/tmcneil-mdb/docs-sample-apps.git
```

2. Checkout my branch
```sh
git checkout python-backend-setup
```

4. Verify you are on the right branch
```sh
git branch
```
5. In the root directory. /python, make a virtual environment.
```sh
python -m venv .venv
```
6. Activate the virtual environment
```sh
source .venv/bin/activate
```
7. Navigate back to /python, install the required packages.
```sh
pip install -r requirements.txt
```
8. Create an .env file at the /python root.
It should have this format:
```python
MONGO_URI="place your connection string here"
MONGO_DB="sample_mflix"
```
9. Navigate back to the root and start the server.
```sh
fastapi dev main.py or uvicorn main:app --reload
```
(NOTE: THESE WONT WORK IF THE VIRTUAL ENVIRONMENT IS NOT ACTIVATED)
10. Click the link in the terminal or visit ```localhost:8000/docs```
11. Try visiting ```localhost:8000/api/movies```.

If the setup ran correctly, you should see data 🎉

*I recommend having your atlas instance up to explore your data and query the db directly.*

**Troubleshooting**: If commands fail, ensure your virtual environment is activated (you should see `(.venv)` in your terminal prompt).


## Learning FastAPI
Before diving into the repo, I suggest spending some time with the official [FastAPI tutorial](https://fastapi.tiangolo.com/tutorial/).

You only need to read up to the 'Request Body' section to get comfortable. *The query parameters and path parameters section can be read later.*

Key Takeaways:
- Decorators (@app.get, @app.post,etc.)
- Query, path, and body parameters
- Pydantic validation/ serialization
- Automatic JSON responses
- Built-in docs and testing at '/docs'


## Exploring the Codebase
Once you have completed the tutorial, I would suggest exploring the code and just noticing the differences between Express and Python. The apps are setup similarly but there are some small differences.

### Architecture
|Layer|Purpose|Express Equivalent| Differences|
|:---|:-------|:----------|:------|
|Routes <br> `src/routers/movies.py`| Defines all /movies endpoints (GET, POST, PUT, etc.)| /controllers/movieController.ts |The movies.ts file inside the routes file in the Express backend it actually wiring up the endpoints. Fast handles this for us in the main.py in one line. ```app.include_router(movies.router, prefix="/api/movies", tags=["movies"])```|
|Models <br> `src/models/models.py`| Pydantic schema for validating and serializing request/response data.| /types/index.ts|There are some differences in how the models are constructed. Take note on how nested classes are handled.|
|Utils <br> `src/utils/errorHandler.py`| Centralized utilities for responses, error handling and MongoDB exception mapping.|utils/errorHandler.ts |Express requires devs to write exception handling and validation on their own. Pydanic handles the validation and exception handling is a bit cleaner in Fast. You will notice the most differences here.|
|Database <br>`src/database/mongo_client.py`| Handles the connection to the db|/config/database.ts| *The current database file does not have feature parity with the Express version*|


## Feature Parity Status
|Feature|Status|Owner|Notes|
|:------|:-----|:----|:----|
|Global Exception Handling| DONE| - |Found in Utils |
|JSON Response Matching| DONE | - |Found in Utils|
|CRUD- ```insertOne()```| Not Started| Angela| - |
|CRUD- ```insertMany()```| Not Started| Taylor| - |
|CRUD- ```findOne()```| Not Started| Angela| - |
|CRUD- ```find()```| DONE| - | Found in movies.py as ```get_all_movies()``` This is a good function to look at to understand query parameters, requests and responses. Your functions will be simpler than this. But that is a good base to start with.|
|CRUD- ```updateOne()```| Not Started| Angela| - |
|CRUD- ```updateMany()```| Not Started| Taylor| - |
|CRUD- ```deleteOne()```| Not Started| Angela| - |
|CRUD- ```deleteMany()```| Not Started| Taylor| -|
|CRUD- ```findOne()```| Not Started| Angela| - |
|CRUD- ```findOneAndDelete()```| Not Started| Angela| This one is a bit harder but I figure this could be a fun challenge.|


## Nice to Know
### Utilities (errorHandler.py)
This module provides a parity replacement for the Express errorHandler.ts file. It provides the same response shapes and error handling and removes the middleware.

- create_success_response(data,message) - creates a success response with the same shape as the Express version.
- create_error_response(message,code,details) - creates a error response with the same shape as the Express version.
- parse_mongo_exception(exc) - ensures PyMongo exceptions return JSON identical to the Express Version
- register_error_handlers - hooks our error system into the Fast app

Fast automatically handles async and validation errors, so there is no need for asyncHandler or validateRequiredFields from the TS version.

### Useful Links
- [Main Repo]( https://github.com/mongodb/docs-sample-apps/tree/main )
- [Sample App Scoping Doc](https://docs.google.com/document/d/12dROckw_Cp0ku2IIGku-ch7MvEuBPo0V4Gs-5wQgeHQ/edit?tab=t.0)
- [Sample App Project Description & Breakdown Doc](https://docs.google.com/document/d/1xv2dmcNrT-HYk5TBE-KtVDPmW0274rpBZ0_0QmC66ac/edit?tab=t.0#heading=h.ki9tatw08ilc)
34 changes: 34 additions & 0 deletions server/python/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from fastapi import FastAPI
from src.routers import movies
from src.utils.errorHandler import register_error_handlers

app = FastAPI()
register_error_handlers(app)
app.include_router(movies.router, prefix="/api/movies", tags=["movies"])








#------------------------------------
# Testing error endpoints. Will be removed later
#------------------------------------

'''
@app.get("/")
async def root():
return {"message": "Backend is running!"}

@app.get("/test-duplicate")
async def test_duplicate():
from pymongo.errors import DuplicateKeyError
raise DuplicateKeyError("This is a test duplicate key error.")

@app.get("/test-generic")
async def test_generic():
from pymongo.errors import PyMongoError
raise PyMongoError("This is a test generic pymongo error.")
'''
56 changes: 56 additions & 0 deletions server/python/requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# ==============================================================================
# 1. CORE WEB FRAMEWORK & ASGI SERVER
# FastAPI and its main components.
# ------------------------------------------------------------------------------
fastapi~=0.120.0 # The main web framework
starlette~=0.48.0 # FastAPI's underlying ASGI toolkit
uvicorn~=0.38.0 # Production-ready ASGI server
uvloop~=0.22.0 # Optional: High-performance event loop for uvicorn
websockets~=15.0.0 # For WebSocket support
watchfiles~=1.1.0 # For hot-reloading in development

# ==============================================================================
# 2. DATA VALIDATION & CORE UTILITIES
# Primary libraries for data models and environment config.
# ------------------------------------------------------------------------------
pydantic~=2.12.0 # Data validation and settings management
python-dotenv~=1.1.0 # For loading configuration from .env files
python-multipart~=0.0.0 # For parsing form data and file uploads
PyYAML~=6.0.0 # For handling YAML configuration or data

# ==============================================================================
# 3. DATABASE & CONNECTIVITY
# Database driver and necessary utilities.
# ------------------------------------------------------------------------------
pymongo~=4.15.0 # MongoDB driver
dnspython~=2.8.0 # Required for SRV record lookups by pymongo (e.g., MongoDB Atlas)

# ==============================================================================
# 4. HTTP CLIENT & UTILITIES
# Primary libraries for making external HTTP requests.
# ------------------------------------------------------------------------------
httpx~=0.28.0 # Asynchronous HTTP client for requests to external APIs
email-validator~=2.3.0 # Utility for validating email addresses

# ==============================================================================
# 5. CLI & DEVELOPMENT TOOLS
# Tools for building command-line interfaces for management tasks.
# ------------------------------------------------------------------------------
typer~=0.20.0 # Library for creating command-line applications
fastapi-cli~=0.0.0 # Tools to run and manage FastAPI projects
fastapi-cloud-cli~=0.3.0 # Tools for cloud deployment (specific to your pipeline)

# ==============================================================================
# 6. TESTING & MONITORING
# Frameworks for ensuring code quality and production health.
# ------------------------------------------------------------------------------
pytest~=8.4.0 # Primary testing framework
pytest-asyncio~=1.2.0 # Plugin to make asynchronous tests easy with pytest
sentry-sdk~=2.42.0 # For error tracking and performance monitoring

# ==============================================================================
# 7. LOGGING AND TERMINAL OUTPUT
# Libraries for rich console output and debugging.
# ------------------------------------------------------------------------------
rich~=14.2.0 # For rich, formatted terminal output
rich-toolkit~=0.15.0 # Extensions for the 'rich' library
154 changes: 154 additions & 0 deletions server/python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#
# This file is autogenerated by pip-compile with Python 3.13
# by the following command:
#
# pip-compile requirements.in
#
annotated-doc==0.0.3
# via fastapi
annotated-types==0.7.0
# via pydantic
anyio==4.11.0
# via
# httpx
# starlette
# watchfiles
certifi==2025.10.5
# via
# httpcore
# httpx
# sentry-sdk
click==8.3.0
# via
# rich-toolkit
# typer
# uvicorn
dnspython==2.8.0
# via
# -r requirements.in
# email-validator
# pymongo
email-validator==2.3.0
# via
# -r requirements.in
# pydantic
fastapi==0.120.0
# via -r requirements.in
fastapi-cli==0.0.14
# via -r requirements.in
fastapi-cloud-cli==0.3.1
# via -r requirements.in
h11==0.16.0
# via
# httpcore
# uvicorn
httpcore==1.0.9
# via httpx
httptools==0.7.1
# via uvicorn
httpx==0.28.1
# via
# -r requirements.in
# fastapi-cloud-cli
idna==3.11
# via
# anyio
# email-validator
# httpx
iniconfig==2.3.0
# via pytest
markdown-it-py==4.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
packaging==25.0
# via pytest
pluggy==1.6.0
# via pytest
pydantic[email]==2.12.3
# via
# -r requirements.in
# fastapi
# fastapi-cloud-cli
pydantic-core==2.41.4
# via pydantic
pygments==2.19.2
# via
# pytest
# rich
pymongo==4.15.3
# via -r requirements.in
pytest==8.4.2
# via
# -r requirements.in
# pytest-asyncio
pytest-asyncio==1.2.0
# via -r requirements.in
python-dotenv==1.1.1
# via
# -r requirements.in
# uvicorn
python-multipart==0.0.20
# via -r requirements.in
pyyaml==6.0.3
# via
# -r requirements.in
# uvicorn
rich==14.2.0
# via
# -r requirements.in
# rich-toolkit
# typer
rich-toolkit==0.15.1
# via
# -r requirements.in
# fastapi-cli
# fastapi-cloud-cli
rignore==0.7.1
# via fastapi-cloud-cli
sentry-sdk==2.42.1
# via
# -r requirements.in
# fastapi-cloud-cli
shellingham==1.5.4
# via typer
sniffio==1.3.1
# via anyio
starlette==0.48.0
# via
# -r requirements.in
# fastapi
typer==0.20.0
# via
# -r requirements.in
# fastapi-cli
# fastapi-cloud-cli
typing-extensions==4.15.0
# via
# fastapi
# pydantic
# pydantic-core
# rich-toolkit
# typer
# typing-inspection
typing-inspection==0.4.2
# via pydantic
urllib3==2.5.0
# via sentry-sdk
uvicorn[standard]==0.38.0
# via
# -r requirements.in
# fastapi-cli
# fastapi-cloud-cli
uvloop==0.22.1
# via
# -r requirements.in
# uvicorn
watchfiles==1.1.1
# via
# -r requirements.in
# uvicorn
websockets==15.0.1
Comment thread
tmcneil-mdb marked this conversation as resolved.
# via
# -r requirements.in
# uvicorn
Loading