# 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