Convert all API endpoint URLs to SX expression format

Every URL at sx-web.org now uses bracketed SX expressions — pages AND
API endpoints. defhandler :path values, sx-get/sx-post/sx-delete attrs,
code examples, and Python route decorators all converted.

- Add SxAtomConverter to handlers.py for parameter matching inside
  expression URLs (e.g. /(api.(item.<sx:item_id>)))
- Convert ~50 defhandler :path values in ref-api.sx and examples.sx
- Convert ~90 sx-get/sx-post/sx-delete URLs in reference.sx, examples.sx
- Convert ~30 code example URLs in examples-content.sx
- Convert ~30 API URLs in pages.py (Python string code examples)
- Convert ~70 page navigation URLs in pages.py
- Convert 7 Python route decorators in routes.py
- Convert ~10 reactive API URLs in marshes.sx
- Add API redirect patterns to sx_router.py (301 for old paths)
- Remove /api/ skip in app.py redirects (old API paths now redirect)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 10:02:26 +00:00
parent da1ca6009a
commit feecbb66ba
11 changed files with 358 additions and 299 deletions

View File

@@ -23,7 +23,7 @@ def register(url_prefix: str = "/") -> Blueprint:
# SSE stays in Python — fundamentally different paradigm (async generator).
# ------------------------------------------------------------------
@bp.get("/geography/hypermedia/reference/api/sse-time")
@bp.get("/(geography.(hypermedia.(reference.(api.sse-time))))")
async def ref_sse_time():
async def generate():
for _ in range(30): # stream for 60 seconds max
@@ -38,7 +38,7 @@ def register(url_prefix: str = "/") -> Blueprint:
_marsh_sale_idx = {"n": 0}
@bp.get("/geography/reactive/api/flash-sale")
@bp.get("/(geography.(reactive.(api.flash-sale)))")
async def api_marsh_flash_sale():
from shared.sx.helpers import sx_response
prices = [14.99, 9.99, 24.99, 12.49, 7.99, 29.99, 4.99, 16.50]
@@ -60,7 +60,7 @@ def register(url_prefix: str = "/") -> Blueprint:
_settle_counter = {"n": 0}
@bp.get("/geography/reactive/api/settle-data")
@bp.get("/(geography.(reactive.(api.settle-data)))")
async def api_settle_data():
from shared.sx.helpers import sx_response
_settle_counter["n"] += 1
@@ -76,7 +76,7 @@ def register(url_prefix: str = "/") -> Blueprint:
# --- Demo 4: signal-bound URL endpoints ---
@bp.get("/geography/reactive/api/search/products")
@bp.get("/(geography.(reactive.(api.search-products)))")
async def api_search_products():
from shared.sx.helpers import sx_response
q = request.args.get("q", "")
@@ -95,7 +95,7 @@ def register(url_prefix: str = "/") -> Blueprint:
)
return sx_response(sx_src)
@bp.get("/geography/reactive/api/search/events")
@bp.get("/(geography.(reactive.(api.search-events)))")
async def api_search_events():
from shared.sx.helpers import sx_response
q = request.args.get("q", "")
@@ -114,7 +114,7 @@ def register(url_prefix: str = "/") -> Blueprint:
)
return sx_response(sx_src)
@bp.get("/geography/reactive/api/search/posts")
@bp.get("/(geography.(reactive.(api.search-posts)))")
async def api_search_posts():
from shared.sx.helpers import sx_response
q = request.args.get("q", "")
@@ -135,7 +135,7 @@ def register(url_prefix: str = "/") -> Blueprint:
# --- Demo 5: marsh transform endpoint ---
@bp.get("/geography/reactive/api/catalog")
@bp.get("/(geography.(reactive.(api.catalog)))")
async def api_catalog():
from shared.sx.helpers import sx_response
items = [