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 pymongo to [project.optional-dependencies] in pyproject.toml.
-
Add try-except blocks in app/db/data.py to prevent ModuleNotFoundError if 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 in main.py instead of in every file.
-
Unified Redirects: Remove the duplicate /{short_code} route from fast_api.py and keep only the one in main.py.
-
Lifecycle Management: Use FastAPI lifespan to connect to the DB once at boot, rather than checking/reconnecting inside individual routes.
-
Clean up create_short_url logic: * Flatten the nested try-except and if-else blocks in main.py to avoid updating request.session in 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.toml to move pymongo from dependencies (or dev-groups) to [project.optional-dependencies].
- This allows users to install the core app with
pip install . and only install database support if needed via pip install .[mongodb].
2. Implement Defensive Imports
- Modify
app/db/data.py to wrap the pymongo import in a try-except ImportError block.
- Introduce a global boolean
MONGO_INSTALLED to track availability.
- Goal: Prevent
ModuleNotFoundError when the app starts without the library.
3. Unified Error Handling & Offline Mode
- Refactor
app/main.py and app/api/fast_api.py to check db_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 in main.py.
- Remove duplicate redirect logic in
fast_api.py and let the main app handle all /{short_code} traffic.
- Move database connection logic into a FastAPI
lifespan event to ensure it only attempts to connect once at startup.
5. Update Documentation
- Update
README.md to 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
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
pyproject.tomlto movepymongofromdependencies(ordev-groups) to[project.optional-dependencies].pip install .and only install database support if needed viapip install .[mongodb].2. Implement Defensive Imports
app/db/data.pyto wrap thepymongoimport in atry-except ImportErrorblock.MONGO_INSTALLEDto track availability.ModuleNotFoundErrorwhen the app starts without the library.3. Unified Error Handling & Offline Mode
app/main.pyandapp/api/fast_api.pyto checkdb_available()before executing queries.4. Remove Code Redundancy
load_env()calls into a single entry point inmain.py.fast_api.pyand let the main app handle all/{short_code}traffic.lifespanevent to ensure it only attempts to connect once at startup.5. Update Documentation
README.mdto explain the new installation command for MongoDB users.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.pyand the points for your GitHub issue.1. Updated
app/db/data.pyThis version uses a "Defensive Import" strategy. It won't crash if
pymongois missing; it will simply flag the database as unavailable.What browsers are you seeing the problem on?
No response
Relevant log output
Contact Details
No response
Code of Conduct