-
Notifications
You must be signed in to change notification settings - Fork 0
Description
What happened?
To ensure your project remains functional for everyone—even those who don't want to install MongoDB—you need to implement "graceful degradation." This means the app detects the missing library and simply disables those features instead of crashing.
-
Implement Optional Dependency Support: * Move
pymongoto[project.optional-dependencies]inpyproject.toml. -
Add
try-exceptblocks inapp/db/data.pyto preventModuleNotFoundErrorif the user chooses not to install MongoDB. -
Enable "Graceful Degradation" (Offline Mode):
-
Ensure the UI still loads if
db_available()is False. -
If no DB is present, the app should still generate short URLs (stored only in the user session/memory) instead of showing an error page.
-
Remove Code Redundancy:
-
Environment Loading: Call
load_env()once inmain.pyinstead of in every file. -
Unified Redirects: Remove the duplicate
/{short_code}route fromfast_api.pyand keep only the one inmain.py. -
Lifecycle Management: Use FastAPI
lifespanto connect to the DB once at boot, rather than checking/reconnecting inside individual routes. -
Clean up
create_short_urllogic: * Flatten the nestedtry-exceptandif-elseblocks inmain.pyto avoid updatingrequest.sessionin multiple redundant places.
What did you expect to happen?
Problem: Currently, the application has a hard dependency on pymongo. If the package is not installed or the database is unreachable, the application fails to start or crashes during runtime.
Proposed Changes:
1. Move MongoDB to Optional Dependencies
- Update
pyproject.tomlto movepymongofromdependencies(ordev-groups) to[project.optional-dependencies]. - This allows users to install the core app with
pip install .and only install database support if needed viapip install .[mongodb].
2. Implement Defensive Imports
- Modify
app/db/data.pyto wrap thepymongoimport in atry-except ImportErrorblock. - Introduce a global boolean
MONGO_INSTALLEDto track availability. - Goal: Prevent
ModuleNotFoundErrorwhen the app starts without the library.
3. Unified Error Handling & Offline Mode
- Refactor
app/main.pyandapp/api/fast_api.pyto checkdb_available()before executing queries. - If MongoDB is missing or disconnected, the UI should:
- Display a warning banner: "Running in Limited Mode (No Database)".
- Allow URL shortening using volatile in-memory generation (short-term session use).
- Disable the "Recent URLs" table gracefully instead of throwing a 500 error.
4. Remove Code Redundancy
- Consolidate
load_env()calls into a single entry point inmain.py. - Remove duplicate redirect logic in
fast_api.pyand let the main app handle all/{short_code}traffic. - Move database connection logic into a FastAPI
lifespanevent to ensure it only attempts to connect once at startup.
5. Update Documentation
- Update
README.mdto explain the new installation command for MongoDB users. - Add a troubleshooting section for "Offline Mode."
Anything else we need to know?
To help you clean up the code and handle the optional dependency issue, here is a breakdown of the key changes for your app/db/data.py and the points for your GitHub issue.
1. Updated app/db/data.py
This version uses a "Defensive Import" strategy. It won't crash if pymongo is missing; it will simply flag the database as unavailable.
import os
from typing import Any
# --- DEFENSIVE IMPORT ---
try:
from pymongo import MongoClient
from pymongo.errors import ServerSelectionTimeoutError
MONGO_INSTALLED = True
except ImportError:
# This allows the app to start even if 'pip install pymongo' wasn't run
MONGO_INSTALLED = False
client: Any = None
db: Any = None
urls: Any = None
url_stats: Any = None
def connect_db():
global client, db, urls, url_stats
# 1. Check if the library is even there
if not MONGO_INSTALLED:
print("⚠️ pymongo is not installed. Running in NO-DB mode.")
return False
# 2. Check if the config is there
MONGO_URI = os.getenv("MONGO_URI")
DB_NAME = os.getenv("DATABASE_NAME", "tiny_url")
if not MONGO_URI:
print("⚠️ MONGO_URI missing. Running in NO-DB mode.")
return False
try:
# 3. Short timeout so the UI doesn't hang on startup
client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=2000)
client.admin.command("ping")
db = client[DB_NAME]
urls = db["urls"]
url_stats = db["url_stats"]
print(f"✅ MongoDB connected: '{DB_NAME}'")
return True
except Exception as e:
print(f"⚠️ MongoDB connection failed: {e}. Running in NO-DB mode.")
return False
# REMOVE: connect_db() call from here.
# It's better to call it in the FastAPI lifespan.What browsers are you seeing the problem on?
No response
Relevant log output
Contact Details
No response
Code of Conduct
- I agree to follow this project's Code of Conduct