Spaces:
Runtime error
Runtime error
| # Integrating Real TransitApp API | |
| This guide explains how to replace mock data with real TransitApp API calls. | |
| ## Step 1: Get API Access | |
| 1. Visit https://transitapp.com/apis | |
| 2. Fill out the request form | |
| 3. Wait for approval (usually 1-2 business days) | |
| 4. You'll receive: | |
| - API key | |
| - Base URL (usually `https://api.transitapp.com/v3`) | |
| - Rate limits: 5 calls/minute, 1,500/month (free tier) | |
| ## Step 2: Configure Environment | |
| Add to your `.env` file: | |
| ```bash | |
| TRANSIT_API_KEY=your_actual_api_key_here | |
| ``` | |
| ## Step 3: Update API Functions | |
| ### Example: get_nearby_transit with Real API | |
| Replace the mock implementation in `app.py` with: | |
| ```python | |
| def get_nearby_transit( | |
| latitude: float, | |
| longitude: float, | |
| radius: int = 500, | |
| transport_types: str = "all" | |
| ) -> str: | |
| """Get nearby transit using real TransitApp API""" | |
| if not TRANSIT_API_KEY: | |
| return json.dumps({ | |
| "error": "TRANSIT_API_KEY not configured", | |
| "note": "Running in demo mode with mock data" | |
| }) | |
| try: | |
| # TransitApp API endpoint for nearby transit | |
| url = f"{TRANSIT_API_BASE}/stops/nearby" | |
| headers = { | |
| "X-API-Key": TRANSIT_API_KEY, | |
| "Content-Type": "application/json" | |
| } | |
| params = { | |
| "lat": latitude, | |
| "lon": longitude, | |
| "radius": radius, | |
| "types": transport_types if transport_types != "all" else None | |
| } | |
| response = requests.get(url, headers=headers, params=params, timeout=10) | |
| response.raise_for_status() | |
| data = response.json() | |
| # Transform to our expected format | |
| result = { | |
| "location": {"lat": latitude, "lon": longitude}, | |
| "radius_meters": radius, | |
| "timestamp": datetime.now().isoformat(), | |
| "nearby_lines": [] | |
| } | |
| # Map TransitApp response to our format | |
| for stop in data.get("stops", []): | |
| for route in stop.get("routes", []): | |
| result["nearby_lines"].append({ | |
| "type": route.get("type"), | |
| "route_number": route.get("short_name"), | |
| "route_name": route.get("long_name"), | |
| "direction": route.get("headsign"), | |
| "next_arrivals": [ | |
| f"{arrival['minutes']} min" | |
| for arrival in route.get("arrivals", [])[:3] | |
| ], | |
| "stop_name": stop.get("name"), | |
| "stop_distance_meters": stop.get("distance"), | |
| "realtime": route.get("realtime", False), | |
| "crowdsourced_location": route.get("go_enabled", False) | |
| }) | |
| return json.dumps(result, indent=2) | |
| except requests.exceptions.RequestException as e: | |
| logger.error(f"API request failed: {e}") | |
| return json.dumps({ | |
| "error": f"API request failed: {str(e)}", | |
| "fallback": "Using mock data" | |
| }) | |
| except Exception as e: | |
| logger.error(f"Error in get_nearby_transit: {e}") | |
| return json.dumps({"error": str(e)}) | |
| ``` | |
| ## Step 4: TransitApp API Endpoints Reference | |
| Based on their API documentation, key endpoints include: | |
| ### Nearby Stops/Stations | |
| ``` | |
| GET /v3/stops/nearby | |
| Parameters: | |
| - lat: latitude | |
| - lon: longitude | |
| - radius: search radius in meters | |
| - types: comma-separated (bus,metro,train,bike) | |
| ``` | |
| ### Trip Planning | |
| ``` | |
| POST /v3/routes | |
| Body: | |
| - origin: {lat, lon} | |
| - destination: {lat, lon} | |
| - time: departure time (ISO format or "now") | |
| - modes: array of allowed modes | |
| - preferences: {fastest|cheapest|fewest_transfers} | |
| ``` | |
| ### Real-time Vehicle Positions | |
| ``` | |
| GET /v3/vehicles/{route_id} | |
| Parameters: | |
| - route_id: route identifier | |
| - direction: 0 (outbound) or 1 (inbound) | |
| ``` | |
| ### Service Alerts | |
| ``` | |
| GET /v3/alerts | |
| Parameters: | |
| - lat: latitude | |
| - lon: longitude | |
| - radius: search radius | |
| - severity: alert severity filter | |
| ``` | |
| ## Step 5: Rate Limiting | |
| Implement rate limiting to stay within API limits: | |
| ```python | |
| import time | |
| from functools import wraps | |
| class RateLimiter: | |
| def __init__(self, calls_per_minute=5): | |
| self.calls_per_minute = calls_per_minute | |
| self.calls = [] | |
| def __call__(self, func): | |
| @wraps(func) | |
| def wrapper(*args, **kwargs): | |
| now = time.time() | |
| # Remove calls older than 1 minute | |
| self.calls = [c for c in self.calls if now - c < 60] | |
| if len(self.calls) >= self.calls_per_minute: | |
| # Wait until oldest call expires | |
| sleep_time = 60 - (now - self.calls[0]) | |
| logger.warning(f"Rate limit reached, waiting {sleep_time:.1f}s") | |
| time.sleep(sleep_time) | |
| self.calls = [] | |
| self.calls.append(now) | |
| return func(*args, **kwargs) | |
| return wrapper | |
| # Apply to functions | |
| rate_limiter = RateLimiter(calls_per_minute=5) | |
| @rate_limiter | |
| def get_nearby_transit(...): | |
| # Function implementation | |
| pass | |
| ``` | |
| ## Step 6: Caching | |
| Add caching to reduce API calls: | |
| ```python | |
| from functools import lru_cache | |
| import hashlib | |
| def cache_key(*args, **kwargs): | |
| """Generate cache key from arguments""" | |
| key = str(args) + str(sorted(kwargs.items())) | |
| return hashlib.md5(key.encode()).hexdigest() | |
| # Simple in-memory cache | |
| cache = {} | |
| CACHE_TTL = 30 # seconds | |
| def cached_api_call(func): | |
| @wraps(func) | |
| def wrapper(*args, **kwargs): | |
| key = cache_key(*args, **kwargs) | |
| now = time.time() | |
| if key in cache: | |
| result, timestamp = cache[key] | |
| if now - timestamp < CACHE_TTL: | |
| logger.info(f"Cache hit for {func.__name__}") | |
| return result | |
| result = func(*args, **kwargs) | |
| cache[key] = (result, now) | |
| return result | |
| return wrapper | |
| ``` | |
| ## Step 7: Fallback Strategy | |
| When API is unavailable, gracefully degrade: | |
| ```python | |
| def get_nearby_transit_with_fallback(lat, lon, radius, types): | |
| """Try real API, fall back to mock data""" | |
| try: | |
| if TRANSIT_API_KEY: | |
| return get_nearby_transit_real_api(lat, lon, radius, types) | |
| except Exception as e: | |
| logger.warning(f"API failed, using mock data: {e}") | |
| return get_nearby_transit_mock(lat, lon, radius, types) | |
| ``` | |
| ## Step 8: Testing with Real API | |
| ```bash | |
| # Set your API key | |
| export TRANSIT_API_KEY="your_key_here" | |
| # Run tests | |
| python test_server.py | |
| # Start server | |
| python app.py | |
| ``` | |
| ## Step 9: Monitoring | |
| Add logging for API usage: | |
| ```python | |
| class APIMonitor: | |
| def __init__(self): | |
| self.calls_today = 0 | |
| self.calls_minute = 0 | |
| self.errors = 0 | |
| self.reset_daily = None | |
| self.reset_minute = None | |
| def log_call(self, success=True): | |
| now = datetime.now() | |
| # Reset counters if needed | |
| if not self.reset_daily or now.date() > self.reset_daily: | |
| self.calls_today = 0 | |
| self.reset_daily = now.date() | |
| if not self.reset_minute or now - self.reset_minute > timedelta(minutes=1): | |
| self.calls_minute = 0 | |
| self.reset_minute = now | |
| self.calls_today += 1 | |
| self.calls_minute += 1 | |
| if not success: | |
| self.errors += 1 | |
| logger.info( | |
| f"API Usage - Today: {self.calls_today}/1500, " | |
| f"Minute: {self.calls_minute}/5, " | |
| f"Errors: {self.errors}" | |
| ) | |
| monitor = APIMonitor() | |
| ``` | |
| ## Alternative: Open Transit APIs | |
| If you can't get TransitApp API access, use these alternatives: | |
| ### GTFS-RT Feeds (Free) | |
| Many cities publish free GTFS Realtime feeds: | |
| - NYC MTA: https://api.mta.info | |
| - SF Bay Area: https://511.org/open-data | |
| - London TfL: https://api.tfl.gov.uk | |
| - Paris RATP: https://data.iledefrance-mobilites.fr | |
| ### OpenTripPlanner (Open Source) | |
| Self-host a routing engine: | |
| - http://www.opentripplanner.org/ | |
| - Supports GTFS data | |
| - Can combine multiple feeds | |
| ### HERE Public Transit API | |
| Commercial but has free tier: | |
| - https://developer.here.com/documentation/public-transit/ | |
| - Good global coverage | |
| ## Resources | |
| - TransitApp API Docs: https://api-doc.transitapp.com/ | |
| - GTFS Specification: https://gtfs.org/ | |
| - GTFS-Realtime: https://gtfs.org/realtime/ | |
| - Transit APIs Collection: https://github.com/public-transport/ | |
| ## Support | |
| If you run into issues: | |
| 1. Check API key is correctly set | |
| 2. Verify rate limits not exceeded | |
| 3. Check API endpoint URLs | |
| 4. Review response formats | |
| 5. Enable debug logging | |
| For TransitApp API support: | |
| - Email: api@transitapp.com | |
| - API Status: Check their status page | |