Goal: Convert all 47 contaminated endpoints to JSON-only responses
Current State: 47/92 endpoints (51%) have dual JSON/HTML response logic Target State: 100% JSON-only responses (except file downloads) Estimated Time: 4-6 hours
File: backend/app/api/v1/endpoints/batch.py
Lines: 154-522 (public_router section)
Endpoints to Fix:
- ❌ POST /public/batch/ (line 154)
- ❌ GET /public/batch/ (line 227)
- ❌ GET /public/batch/{id} (line 272)
- ❌ POST /public/batch/{id}/import (line 303)
- ❌ POST /public/batch/{id}/cancel (line 361)
- ❌ POST /public/batch/{id}/retry (line 409)
- ✅ GET /public/batch/{id}/export (line 479) - FileResponse, OK
Changes Required:
# REMOVE this pattern:
hx_request: Optional[str] = Header(None)
if hx_request:
return HTMLResponse(content=f"""...""")
# KEEP only:
return {json_response}Templates to DELETE (after fixing):
templates/partials/active-batches.htmltemplates/partials/batch-history.htmltemplates/partials/batch-details.html
File: backend/app/api/v1/endpoints/kits.py
Lines: 96-542
Endpoints to Fix:
- ❌ GET /kits (line 96)
- ❌ GET /kits/{id} (line 188)
- ❌ POST /kits/{id}/assign (line 316)
- ❌ GET /kits/{id}/recommendations/{pad} (line 449)
Changes:
# REMOVE:
hx_request: Optional[str] = Header(None)
# REMOVE:
if hx_request:
return templates.TemplateResponse("kits/kit-list.html", {...})
# RETURN only JSON:
return KitListResponse(...)Templates to DELETE:
templates/kits/kit-list.htmltemplates/kits/kit-detail.htmltemplates/kits/pad-assignment.htmltemplates/kits/recommendations-dropdown.html
File: backend/app/api/v1/endpoints/sp404_export.py
Lines: 49-539
Endpoints to Fix:
- ❌ POST /sp404/samples/{id}/export (line 49)
- ❌ POST /sp404/samples/export-batch (line 144)
- ❌ POST /sp404/kits/{kit_id}/export (line 259)
- ❌ GET /sp404/exports (line 481)
Templates to DELETE:
templates/sp404/export-result.htmltemplates/sp404/export-progress.htmltemplates/sp404/export-list.html
File: backend/app/api/v1/endpoints/samples.py
Lines: 93-544
Endpoints to Fix:
- ❌ GET /samples/ (line 93)
- ❌ GET /public/samples/ (line 417)
- ❌ POST /public/samples/{id}/analyze (line 204)
Changes:
# Line 93-163 - list_samples()
# REMOVE lines 147-153 (HTMX response)
# KEEP lines 156-162 (JSON response)
# Line 417-484 - list_samples_public()
# REMOVE lines 467-474 (HTMX response)
# KEEP lines 477-483 (JSON response)Templates to DELETE:
templates/partials/sample-grid.html
File: backend/app/api/v1/endpoints/public.py
Lines: 19-256
Endpoints to Fix:
- ❌ GET /public/samples/ (line 19)
- ❌ POST /public/samples/ (line 124)
- ❌ POST /public/samples/{id}/analyze (line 204)
Note: This duplicates functionality from samples.py public_router Consider: Deleting this entire file and using samples.py public endpoints instead
File: backend/app/api/v1/endpoints/preferences.py
Lines: 41-147
Endpoints to Fix:
- ❌ GET /preferences (line 41)
- ❌ PATCH /preferences (line 72)
Templates to DELETE:
templates/preferences/preferences-form.htmltemplates/preferences/preferences-success.html
-
Locate the endpoint function
-
Remove the
hx_requestparameter:# REMOVE: hx_request: Optional[str] = Header(None)
-
Delete the HTMX conditional block:
# DELETE: if hx_request: return templates.TemplateResponse(...)
-
Keep only the JSON return:
# KEEP: return { "items": items, "total": total, ... }
-
Verify imports (remove if unused):
# May be able to remove: from fastapi import Header, Request from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates
-
Test the endpoint (after all fixes):
curl -s http://localhost:8100/api/v1/endpoint | jq .
After fixing all endpoints, run:
# Create: scripts/cleanup-htmx.sh
#!/bin/bash
echo "🧹 Cleaning up HTMX artifacts..."
# Remove template directories
rm -rf backend/templates/partials/
rm -rf backend/templates/kits/
rm -rf backend/templates/sp404/
rm -rf backend/templates/preferences/
# Remove template config if no templates remain
REMAINING=$(find backend/templates -name "*.html" | wc -l)
if [ "$REMAINING" -eq 0 ]; then
echo "No templates remaining - safe to remove templates directory"
rm -rf backend/templates/
# Remove template imports from main.py
sed -i '' '/templates/d' backend/app/main.py
sed -i '' '/Jinja2Templates/d' backend/app/main.py
fi
echo "✅ Cleanup complete"After all fixes, run:
# Create: scripts/validate-json-responses.py
import requests
import json
BASE_URL = "http://localhost:8100"
ENDPOINTS = [
("GET", "/api/v1/kits"),
("GET", "/api/v1/samples"),
("GET", "/api/v1/preferences"),
("GET", "/api/v1/public/samples/"),
("GET", "/api/v1/public/batch/"),
("GET", "/api/v1/sp404/exports"),
# ... all 92 endpoints
]
failed = []
for method, endpoint in ENDPOINTS:
try:
resp = requests.request(method, f"{BASE_URL}{endpoint}")
# Check it's not HTML
if resp.text.startswith("<"):
failed.append(f"{method} {endpoint}: Returns HTML")
continue
# Check it's valid JSON
json.loads(resp.text)
print(f"✓ {method} {endpoint}")
except json.JSONDecodeError:
failed.append(f"{method} {endpoint}: Invalid JSON")
except Exception as e:
failed.append(f"{method} {endpoint}: {str(e)}")
if failed:
print(f"\n❌ FAILED: {len(failed)} endpoints")
for f in failed:
print(f" - {f}")
exit(1)
else:
print(f"\n✅ SUCCESS: All {len(ENDPOINTS)} endpoints return JSON")- Identify all contaminated endpoints (47 found)
- Create fix plan
- Create backup branch:
git checkout -b backup/before-htmx-removal
- Fix batch.py (7 endpoints)
- Fix kits.py (4 endpoints)
- Fix sp404_export.py (4 endpoints)
- Fix samples.py (3 endpoints)
- Fix public.py (3 endpoints)
- Fix preferences.py (2 endpoints)
- Remove unused imports
- Delete template files
- Run validation script
- Test all user workflows
- Update API documentation
- All endpoints return JSON
- No HTML responses
- WebSocket connections work
- React app can consume all APIs
- No console errors
| Task | Time |
|---|---|
| Fix batch.py | 45 min |
| Fix kits.py | 30 min |
| Fix sp404_export.py | 30 min |
| Fix samples.py | 20 min |
| Fix public.py | 20 min |
| Fix preferences.py | 15 min |
| Remove templates | 10 min |
| Validation testing | 1 hour |
| Total | 3.5-4 hours |
Once all 47 endpoints are fixed:
- Phase 2: Remove
frontend/directory (old HTMX UI) - Phase 3: Update documentation
- Phase 4: Deploy React-only app
Created: 2025-11-18 Status: Ready to execute