Remove deprecated /request route prefix support (#318)

This commit removes all references to the deprecated /request route
prefix
that was previously used for dual routing. The following changes were
made:

- Removed register_dual_routes() function that registered routes with
/request prefix
- Removed url_for_with_request() helper function for generating /request
URLs
- Removed call to register_dual_routes(app) at application startup
- Removed /request/ prefixed favicon routes
- Updated StatusEndpointFilter to remove /request/api/status log
filtering
- Removed unused flask_url_for import

All routes now only use the standard paths without the /request prefix.
This commit is contained in:
CaliBrain
2025-11-16 15:41:29 -05:00
committed by GitHub
parent 289666aeef
commit b02ad7452c
10 changed files with 12 additions and 62 deletions
+1 -1
View File
@@ -110,7 +110,7 @@ EXPOSE ${FLASK_PORT}
# Add healthcheck for container status
# This will run as root initially, but check localhost which should work if the app binds correctly.
HEALTHCHECK --interval=60s --timeout=60s --start-period=60s --retries=3 \
CMD curl -s http://localhost:${FLASK_PORT}/request/api/status > /dev/null || exit 1
CMD curl -s http://localhost:${FLASK_PORT}/api/status > /dev/null || exit 1
# Use dumb-init as the entrypoint to handle signals properly
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+2 -46
View File
@@ -12,7 +12,6 @@ from flask_socketio import SocketIO, emit
from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.security import check_password_hash
from werkzeug.wrappers import Response
from flask import url_for as flask_url_for
import typing
from logger import setup_logger
@@ -132,10 +131,10 @@ if DEBUG:
class StatusEndpointFilter(logging.Filter):
"""Filter out routine status endpoint requests to reduce log noise."""
def filter(self, record):
# Exclude GET /api/status and GET /request/api/status requests
# Exclude GET /api/status requests
if hasattr(record, 'getMessage'):
message = record.getMessage()
if 'GET /api/status' in message or 'GET /request/api/status' in message:
if 'GET /api/status' in message:
return False
return True
@@ -194,44 +193,6 @@ def login_required(f):
return f(*args, **kwargs)
return decorated_function
def register_dual_routes(app : Flask) -> None:
"""
Register each route both with and without the /request prefix.
This function should be called after all routes are defined.
"""
# Store original url_map rules
rules = list(app.url_map.iter_rules())
# Add /request prefix to each rule
for rule in rules:
if rule.rule != '/request/' and rule.rule != '/request': # Skip if it's already a request route
# Create new routes with /request prefix, both with and without trailing slash
base_rule = rule.rule[:-1] if rule.rule.endswith('/') else rule.rule
if base_rule == '': # Special case for root path
app.add_url_rule('/request', f"root_request",
view_func=app.view_functions[rule.endpoint],
methods=rule.methods)
app.add_url_rule('/request/', f"root_request_slash",
view_func=app.view_functions[rule.endpoint],
methods=rule.methods)
else:
app.add_url_rule(f"/request{base_rule}",
f"{rule.endpoint}_request",
view_func=app.view_functions[rule.endpoint],
methods=rule.methods)
app.add_url_rule(f"/request{base_rule}/",
f"{rule.endpoint}_request_slash",
view_func=app.view_functions[rule.endpoint],
methods=rule.methods)
app.jinja_env.globals['url_for'] = url_for_with_request
def url_for_with_request(endpoint : str, **values : typing.Any) -> str:
"""Generate URLs with /request prefix by default."""
if endpoint == 'static' or endpoint == 'serve_frontend_assets':
# For static files, add /request prefix
url = flask_url_for(endpoint, **values)
return f"/request{url}"
return flask_url_for(endpoint, **values)
# Serve frontend static files
@app.route('/assets/<path:filename>')
@@ -259,8 +220,6 @@ def logo() -> Response:
@app.route('/favicon.ico')
@app.route('/favico<path:_>')
@app.route('/request/favico<path:_>')
@app.route('/request/static/favico<path:_>')
def favicon(_ : typing.Any = None) -> Response:
"""
Serve favicon from built frontend assets.
@@ -823,9 +782,6 @@ def catch_all(path: str) -> Response:
# Otherwise serve the React app
return send_from_directory(os.path.join(app.root_path, 'frontend-dist'), 'index.html')
# Register all routes with /request prefix
register_dual_routes(app)
# WebSocket event handlers
@socketio.on('connect')
def handle_connect():
+1 -1
View File
@@ -275,7 +275,7 @@ Checks run every 30 seconds with a 30-second timeout and 3 retries.
You can enable by adding this to your compose :
```
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD pyrequests http://localhost:8084/request/api/status || exit 1
CMD curl -s http://localhost:8084/api/status || exit 1
```
## 📝 Logging
+2 -2
View File
@@ -69,8 +69,8 @@ The development server supports HMR for instant feedback during development.
### API Integration
The frontend communicates with the Flask backend via:
- REST API endpoints (`/request/api/*`)
- WebSocket connection (`ws://localhost:8084/request/ws`)
- REST API endpoints (`/api/*`)
- WebSocket connection (`ws://localhost:8084/ws`)
### Building for Production
The production build is optimized and minified:
@@ -192,7 +192,7 @@ export const DownloadsSidebar = ({
<h3 className="font-semibold text-sm truncate" title={book.title}>
{isCompleted && book.download_path ? (
<a
href={`/request/api/localdownload?id=${encodeURIComponent(book.id)}`}
href={`/api/localdownload?id=${encodeURIComponent(book.id)}`}
className="text-sky-600 hover:underline"
>
{book.title || 'Unknown Title'}
+2 -2
View File
@@ -277,7 +277,7 @@ export const Header = ({
{/* Debug Buttons */}
{debug && (
<>
<form action="/request/debug" method="get" className="w-full">
<form action="/debug" method="get" className="w-full">
<button
className="w-full text-left px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors flex items-center gap-3 text-orange-600 dark:text-orange-400"
type="submit"
@@ -288,7 +288,7 @@ export const Header = ({
<span>Debug</span>
</button>
</form>
<form action="/request/api/restart" method="get" className="w-full">
<form action="/api/restart" method="get" className="w-full">
<button
className="w-full text-left px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors flex items-center gap-3 text-orange-600 dark:text-orange-400"
type="submit"
@@ -114,7 +114,7 @@ export const StatusSection = ({
{Object.values(items).map((book: any) => {
const maybeLinkedTitle = book.download_path ? (
<a
href={`/request/api/localdownload?id=${encodeURIComponent(book.id)}`}
href={`/api/localdownload?id=${encodeURIComponent(book.id)}`}
className="text-blue-600 hover:underline"
>
{book.title || '-'}
+1 -1
View File
@@ -1,6 +1,6 @@
import { Book, StatusData, AppConfig, LoginCredentials, AuthResponse } from '../types';
const API_BASE = '/request/api';
const API_BASE = '/api';
// API endpoints
const API = {
-6
View File
@@ -16,12 +16,6 @@ export default defineConfig({
cors: true,
proxy: {
// Proxy API requests to the Docker backend
'/request/api': {
target: 'http://localhost:8084',
changeOrigin: true,
secure: false,
},
// Also proxy direct API calls (without /request prefix)
'/api': {
target: 'http://localhost:8084',
changeOrigin: true,
+1 -1
View File
@@ -124,7 +124,7 @@ print(f"Verified file exists: {expected_filepath}")
# Step 6 : Download the book
print(f"Step 6: Downloading book {book_id}...")
download_response = requests.get(f"{server_url}/request/api/localdownload?id={book_id}")
download_response = requests.get(f"{server_url}/api/localdownload?id={book_id}")
download_response.raise_for_status()
# Write book to temp file :
temp_file_path = os.path.join("/tmp", f"{book_id}.epub")