feat: Refactor endpoint listing into blueprint
- Moved endpoint listing and searching routes (`list_endpoints`, `search_endpoints`) and helper function (`get_routes`) from `app.py` into a new blueprint at `routes/endpoints.py`. - Added `/endpoints` URL prefix to the blueprint. - Registered the new `endpoints_bp` blueprint in `app.py`. - Removed the original endpoint route definitions and helper function from `app.py`. - Updated `url_for` calls in relevant templates (`endpoints.html`, `base.html`) to reference the new blueprint endpoints (e.g., `endpoints.list_endpoints`). - Updated `templates/changelog/changelog.html` to document this refactoring. ```
This commit is contained in:
49
app.py
49
app.py
@@ -11,6 +11,7 @@ from routes.calendar import calendar_bp # Import the new calendar blueprint
|
|||||||
from routes.notes import notes_bp # Import the new notes blueprint
|
from routes.notes import notes_bp # Import the new notes blueprint
|
||||||
from routes.workout import workout_bp # Import the new workout blueprint
|
from routes.workout import workout_bp # Import the new workout blueprint
|
||||||
from routes.sql_explorer import sql_explorer_bp # Import the new SQL explorer blueprint
|
from routes.sql_explorer import sql_explorer_bp # Import the new SQL explorer blueprint
|
||||||
|
from routes.endpoints import endpoints_bp # Import the new endpoints blueprint
|
||||||
from extensions import db
|
from extensions import db
|
||||||
from utils import convert_str_to_date, generate_plot
|
from utils import convert_str_to_date, generate_plot
|
||||||
from flask_htmx import HTMX
|
from flask_htmx import HTMX
|
||||||
@@ -42,6 +43,7 @@ app.register_blueprint(calendar_bp) # Register the calendar blueprint
|
|||||||
app.register_blueprint(notes_bp) # Register the notes blueprint
|
app.register_blueprint(notes_bp) # Register the notes blueprint
|
||||||
app.register_blueprint(workout_bp) # Register the workout blueprint
|
app.register_blueprint(workout_bp) # Register the workout blueprint
|
||||||
app.register_blueprint(sql_explorer_bp) # Register the SQL explorer blueprint (prefix defined in blueprint file)
|
app.register_blueprint(sql_explorer_bp) # Register the SQL explorer blueprint (prefix defined in blueprint file)
|
||||||
|
app.register_blueprint(endpoints_bp) # Register the endpoints blueprint (prefix defined in blueprint file)
|
||||||
|
|
||||||
@app.after_request
|
@app.after_request
|
||||||
def response_minify(response):
|
def response_minify(response):
|
||||||
@@ -308,53 +310,6 @@ def delete_exercise(exercise_id):
|
|||||||
db.exercises.delete_exercise(exercise_id)
|
db.exercises.delete_exercise(exercise_id)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def get_routes():
|
|
||||||
routes = []
|
|
||||||
for rule in app.url_map.iter_rules():
|
|
||||||
if rule.endpoint == 'static':
|
|
||||||
continue
|
|
||||||
methods = ', '.join(sorted(rule.methods - {'HEAD', 'OPTIONS'}))
|
|
||||||
route_info = {
|
|
||||||
'endpoint': rule.endpoint,
|
|
||||||
'url': rule.rule,
|
|
||||||
'methods': methods,
|
|
||||||
'view_func': app.view_functions[rule.endpoint].__name__,
|
|
||||||
'doc': app.view_functions[rule.endpoint].__doc__
|
|
||||||
}
|
|
||||||
routes.append(route_info)
|
|
||||||
return routes
|
|
||||||
|
|
||||||
@app.route('/endpoints')
|
|
||||||
def list_endpoints():
|
|
||||||
"""
|
|
||||||
Lists all API endpoints available in the Flask application.
|
|
||||||
|
|
||||||
This endpoint retrieves all registered routes, excluding static routes,
|
|
||||||
and displays their details such as endpoint name, URL, allowed HTTP methods,
|
|
||||||
view function name, and a brief description.
|
|
||||||
"""
|
|
||||||
routes = get_routes()
|
|
||||||
|
|
||||||
if htmx:
|
|
||||||
return render_block(app.jinja_env, 'endpoints.html', 'content', routes=routes)
|
|
||||||
return render_template('endpoints.html', routes=routes)
|
|
||||||
|
|
||||||
@app.route('/endpoints/search')
|
|
||||||
def search_endpoints():
|
|
||||||
routes = get_routes()
|
|
||||||
search = request.args.get('search', '').lower()
|
|
||||||
if search:
|
|
||||||
routes = [
|
|
||||||
route for route in routes
|
|
||||||
if search in route['endpoint'].lower()
|
|
||||||
or search in route['url'].lower()
|
|
||||||
or search in route['methods'].lower()
|
|
||||||
or search in route['view_func'].lower()
|
|
||||||
or (route['doc'] and search in route['doc'].lower())
|
|
||||||
]
|
|
||||||
|
|
||||||
return render_template('partials/endpoints_table.html', routes=routes)
|
|
||||||
|
|
||||||
@app.teardown_appcontext
|
@app.teardown_appcontext
|
||||||
def closeConnection(exception):
|
def closeConnection(exception):
|
||||||
db.close_connection()
|
db.close_connection()
|
||||||
|
|||||||
60
routes/endpoints.py
Normal file
60
routes/endpoints.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
from flask import Blueprint, render_template, request, current_app
|
||||||
|
from jinja2_fragments import render_block
|
||||||
|
from flask_htmx import HTMX
|
||||||
|
|
||||||
|
endpoints_bp = Blueprint('endpoints', __name__, url_prefix='/endpoints')
|
||||||
|
htmx = HTMX()
|
||||||
|
|
||||||
|
def _get_routes(app):
|
||||||
|
"""Helper function to extract routes from the Flask app object."""
|
||||||
|
routes = []
|
||||||
|
for rule in app.url_map.iter_rules():
|
||||||
|
# Exclude static routes and HEAD/OPTIONS methods
|
||||||
|
if rule.endpoint == 'static':
|
||||||
|
continue
|
||||||
|
methods = ', '.join(sorted(rule.methods - {'HEAD', 'OPTIONS'}))
|
||||||
|
route_info = {
|
||||||
|
'endpoint': rule.endpoint,
|
||||||
|
'url': rule.rule,
|
||||||
|
'methods': methods,
|
||||||
|
'view_func': app.view_functions[rule.endpoint].__name__,
|
||||||
|
'doc': app.view_functions[rule.endpoint].__doc__
|
||||||
|
}
|
||||||
|
routes.append(route_info)
|
||||||
|
return routes
|
||||||
|
|
||||||
|
@endpoints_bp.route('/')
|
||||||
|
def list_endpoints():
|
||||||
|
"""
|
||||||
|
Lists all API endpoints available in the Flask application.
|
||||||
|
|
||||||
|
This endpoint retrieves all registered routes, excluding static routes,
|
||||||
|
and displays their details such as endpoint name, URL, allowed HTTP methods,
|
||||||
|
view function name, and a brief description.
|
||||||
|
"""
|
||||||
|
# Pass current_app to the helper function
|
||||||
|
routes = _get_routes(current_app)
|
||||||
|
|
||||||
|
if htmx:
|
||||||
|
# Assuming 'endpoints.html' uses a block named 'content'
|
||||||
|
return render_block(current_app.jinja_env, 'endpoints.html', 'content', routes=routes)
|
||||||
|
return render_template('endpoints.html', routes=routes)
|
||||||
|
|
||||||
|
@endpoints_bp.route('/search')
|
||||||
|
def search_endpoints():
|
||||||
|
"""Searches and filters endpoints based on a query."""
|
||||||
|
# Pass current_app to the helper function
|
||||||
|
routes = _get_routes(current_app)
|
||||||
|
search = request.args.get('search', '').lower()
|
||||||
|
if search:
|
||||||
|
routes = [
|
||||||
|
route for route in routes
|
||||||
|
if search in route['endpoint'].lower()
|
||||||
|
or search in route['url'].lower()
|
||||||
|
or search in route['methods'].lower()
|
||||||
|
or search in route['view_func'].lower()
|
||||||
|
or (route.get('doc') and search in route['doc'].lower()) # Safer access to 'doc'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Renders the partial table
|
||||||
|
return render_template('partials/endpoints_table.html', routes=routes)
|
||||||
@@ -172,8 +172,9 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<span class="ml-3">SQL Explorer</span>
|
<span class="ml-3">SQL Explorer</span>
|
||||||
</a>
|
</a>
|
||||||
<a hx-get="{{ url_for('list_endpoints') }}" hx-push-url="true" hx-target="#container"
|
<a hx-get="{{ url_for('endpoints.list_endpoints') }}" hx-push-url="true"
|
||||||
class="text-base text-gray-900 font-normal rounded-lg hover:bg-gray-100 group transition duration-75 flex items-center p-2 cursor-pointer {{ is_selected_page(url_for('list_endpoints')) }} page-link"
|
hx-target="#container"
|
||||||
|
class="text-base text-gray-900 font-normal rounded-lg hover:bg-gray-100 group transition duration-75 flex items-center p-2 cursor-pointer {{ is_selected_page(url_for('endpoints.list_endpoints')) }} page-link"
|
||||||
_="on click add .hidden to #sidebar then remove .ml-64 from #main
|
_="on click add .hidden to #sidebar then remove .ml-64 from #main
|
||||||
on htmx:afterRequest go to the top of the body">
|
on htmx:afterRequest go to the top of the body">
|
||||||
<!-- Server Icon from Heroicons -->
|
<!-- Server Icon from Heroicons -->
|
||||||
|
|||||||
@@ -10,6 +10,15 @@
|
|||||||
<div class="prose max-w-none">
|
<div class="prose max-w-none">
|
||||||
<p>Updates and changes to the site will be documented here, with the most recent changes listed first.</p>
|
<p>Updates and changes to the site will be documented here, with the most recent changes listed first.</p>
|
||||||
|
|
||||||
|
<!-- New Entry for Endpoints Refactoring -->
|
||||||
|
<hr class="my-6">
|
||||||
|
<h2 class="text-xl font-semibold mb-2">March 31, 2025</h2>
|
||||||
|
<ul class="list-disc pl-5 space-y-1">
|
||||||
|
<li>Refactored endpoint listing/searching functionality into its own blueprint (`routes/endpoints.py`
|
||||||
|
with `/endpoints` prefix).</li>
|
||||||
|
<li>Updated relevant `url_for` calls in templates to use the new `endpoints.` prefix.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<!-- New Entry for SQL Explorer Refactoring -->
|
<!-- New Entry for SQL Explorer Refactoring -->
|
||||||
<hr class="my-6">
|
<hr class="my-6">
|
||||||
<h2 class="text-xl font-semibold mb-2">March 31, 2025</h2>
|
<h2 class="text-xl font-semibold mb-2">March 31, 2025</h2>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<!-- Optional: Search or Filter functionality with HTMX -->
|
<!-- Optional: Search or Filter functionality with HTMX -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<input type="text" id="search" name="search" placeholder="Search endpoints..."
|
<input type="text" id="search" name="search" placeholder="Search endpoints..."
|
||||||
class="w-full p-2 border border-gray-300 rounded" hx-get="{{ url_for('search_endpoints') }}"
|
class="w-full p-2 border border-gray-300 rounded" hx-get="{{ url_for('endpoints.search_endpoints') }}"
|
||||||
hx-trigger="keyup changed delay:500ms, search" hx-push-url="true" hx-target="#endpoints-table"
|
hx-trigger="keyup changed delay:500ms, search" hx-push-url="true" hx-target="#endpoints-table"
|
||||||
hx-include="[name='search']">
|
hx-include="[name='search']">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user