feat: implement MCP server and dashboard for football data platform
Add complete Nike football data platform with: - FastMCP server exposing football data tools over HTTP - RapidAPI client for free-api-live-football-data integration - Bootstrap web dashboard with live match/standings views - REST API endpoints for dashboard consumption - Docker support with multi-stage build - Comprehensive README with architecture docs - Minimal .gitignore replacing verbose Python template
This commit is contained in:
75
scripts/test_api.py
Normal file
75
scripts/test_api.py
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test API connectivity, find Toronto FC, and list popular leagues
|
||||
so we can confirm the correct MLS league ID for this API.
|
||||
|
||||
Uses 2 API quota calls.
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from nike import config, api_football
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not config.API_FOOTBALL_KEY:
|
||||
print("❌ API_FOOTBALL_KEY not set in .env")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"API: {config.API_FOOTBALL_BASE}\n")
|
||||
|
||||
# ── 1. Popular leagues (connectivity probe + league ID discovery) ──
|
||||
print("── Popular Leagues ──────────────────────────")
|
||||
try:
|
||||
t0 = time.time()
|
||||
data = api_football._get("football-popular-leagues", timeout=8)
|
||||
latency_ms = round((time.time() - t0) * 1000, 1)
|
||||
except Exception as e:
|
||||
print(f"❌ Not connected: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"✅ Connected latency={latency_ms}ms "
|
||||
f"quota_remaining={api_football.last_quota_remaining()}")
|
||||
|
||||
leagues = (data.get('response', {}).get('popular') or
|
||||
data.get('response', {}).get('leagues') or [])
|
||||
if not isinstance(leagues, list):
|
||||
print(f" Raw response structure:\n{json.dumps(data, indent=2)[:1000]}")
|
||||
else:
|
||||
print(f" {len(leagues)} league(s) returned:")
|
||||
for lg in leagues:
|
||||
lg_id = lg.get('id', '?')
|
||||
lg_name = lg.get('name', str(lg))
|
||||
ccode = lg.get('ccode', '')
|
||||
print(f" [{str(lg_id):>5}] {lg_name} ({ccode})")
|
||||
print(f"\n ↳ Current config.MLS_LEAGUE_ID = {config.MLS_LEAGUE_ID}")
|
||||
print(" Update nike/config.py if the ID above doesn't match MLS.\n")
|
||||
|
||||
# ── 2. Search for Toronto FC ───────────────────────────────────
|
||||
print("── Search: Toronto ──────────────────────────")
|
||||
raw_search = api_football._get("football-teams-search", {"search": "Toronto"})
|
||||
print(f" quota_remaining={api_football.last_quota_remaining()}")
|
||||
|
||||
# Try all common envelope keys; fall back to full raw dump
|
||||
raw_list = (raw_search.get('response', {}).get('suggestions') or
|
||||
raw_search.get('response', {}).get('teams') or
|
||||
raw_search.get('data') or raw_search.get('result'))
|
||||
if not isinstance(raw_list, list) or not raw_list:
|
||||
print(f" 0 results — raw response:\n{json.dumps(raw_search, indent=2)[:1500]}")
|
||||
else:
|
||||
teams = [api_football._normalise_team_item(t)
|
||||
for t in raw_list if t.get('type', 'team') == 'team']
|
||||
print(f" {len(teams)} team result(s):")
|
||||
for item in teams:
|
||||
t = item['team']
|
||||
v = item.get('venue') or {}
|
||||
print(f" [{str(t.get('id')):>6}] {t.get('name')} ({t.get('country')})")
|
||||
if v.get('name'):
|
||||
print(f" Venue: {v.get('name')}, {v.get('city')} cap={v.get('capacity')}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user