UNPKG

ws-dottie

Version:

Your friendly TypeScript companion for Washington State transportation APIs - WSDOT and WSF data with smart caching and React Query integration

604 lines (501 loc) 15.2 kB
# Examples Practical examples and common use cases for WS-Dottie. ## 🚀 Basic Examples ### Node.js Application ```javascript import { WsfVessels, WsdotHighwayAlerts, WsdotApiError } from 'ws-dottie'; async function getTransportationData() { try { // Get vessel locations const vessels = await WsfVessels.getVesselLocations(); console.log(`Found ${vessels.length} vessels`); // Get highway alerts const alerts = await WsdotHighwayAlerts.getHighwayAlerts(); console.log(`Found ${alerts.length} active alerts`); return { vessels, alerts }; } catch (error) { if (error instanceof WsdotApiError) { console.error('API Error:', error.message); } throw error; } } ``` ### React Application ```javascript import { useVesselLocations, useHighwayAlerts, WsdotApiError } from 'ws-dottie'; function TransportationDashboard() { const { data: vessels, isLoading, error } = useVesselLocations(); const { data: alerts } = useHighwayAlerts(); if (error instanceof WsdotApiError) { return <div>API Error: {error.message}</div>; } return ( <div> <h2>Ferries: {vessels?.length || 0}</h2> <h2>Highway Alerts: {alerts?.length || 0}</h2> {isLoading && <div>Loading...</div>} </div> ); } ``` ## 🎯 Common Use Cases ### Ferry Tracking App ```javascript import { useVesselLocations, useTerminalWaitTimes, VesselCacheProvider, TerminalCacheProvider } from 'ws-dottie'; function FerryTracker() { const { data: vessels } = useVesselLocations(); const { data: waitTimes } = useTerminalWaitTimes(); return ( <div> <h1>Ferry Tracker</h1> <h2>Vessels ({vessels?.length || 0})</h2> {vessels?.map(vessel => ( <div key={vessel.VesselID}> <strong>{vessel.VesselName}</strong> <div>Location: {vessel.Latitude}, {vessel.Longitude}</div> <div>Last Update: {vessel.LastUpdate.toLocaleString()}</div> </div> ))} <h2>Terminal Wait Times</h2> {waitTimes?.map(terminal => ( <div key={terminal.TerminalID}> <strong>{terminal.TerminalName}</strong> <div>Wait Time: {terminal.WaitTime} minutes</div> </div> ))} </div> ); } function App() { return ( <QueryClientProvider client={queryClient}> <VesselCacheProvider /> <TerminalCacheProvider /> <FerryTracker /> </QueryClientProvider> ); } ``` ### Traffic Monitoring Dashboard ```javascript import { useHighwayAlerts, useTrafficFlows, useTravelTimes, useTollRates } from 'ws-dottie'; function TrafficDashboard() { const { data: alerts } = useHighwayAlerts(); const { data: flows } = useTrafficFlows(); const { data: travelTimes } = useTravelTimes(); const { data: tollRates } = useTollRates(); return ( <div> <h1>Traffic Dashboard</h1> <h2>Active Alerts ({alerts?.length || 0})</h2> {alerts?.slice(0, 5).map(alert => ( <div key={alert.AlertID}> <strong>{alert.HeadlineDescription}</strong> <div>{alert.EventCategory}</div> </div> ))} <h2>Traffic Flow</h2> {flows?.slice(0, 10).map(flow => ( <div key={flow.FlowStationID}> <strong>{flow.FlowStationLocation}</strong> <div>Speed: {flow.CurrentSpeed} mph</div> </div> ))} <h2>Travel Times</h2> {travelTimes?.slice(0, 5).map(route => ( <div key={route.TravelTimeID}> <strong>{route.Name}</strong> <div>Time: {route.CurrentTime} minutes</div> </div> ))} <h2>Toll Rates</h2> {tollRates?.slice(0, 5).map(rate => ( <div key={rate.TollRateID}> <strong>{rate.TripName}</strong> <div>Rate: ${rate.TollAmount}</div> </div> ))} </div> ); } ``` ### Weather Information Display ```javascript import { useWeatherInformation, useWeatherStations, useMountainPassConditions } from 'ws-dottie'; function WeatherDisplay() { const { data: weather } = useWeatherInformation({ stationIds: [1, 2, 3] }); const { data: stations } = useWeatherStations(); const { data: passConditions } = useMountainPassConditions(); return ( <div> <h1>Weather Information</h1> <h2>Weather Stations ({stations?.length || 0})</h2> {stations?.slice(0, 5).map(station => ( <div key={station.StationID}> <strong>{station.StationName}</strong> <div>Temperature: {station.Temperature}°F</div> <div>Conditions: {station.RoadCondition}</div> </div> ))} <h2>Mountain Passes</h2> {passConditions?.map(pass => ( <div key={pass.MountainPassId}> <strong>{pass.MountainPassName}</strong> <div>Status: {pass.RestrictionOne}</div> <div>Conditions: {pass.RoadCondition}</div> </div> ))} </div> ); } ``` ## 🔧 Advanced Patterns ### Configuration Management ```javascript import { configManager, WsfVessels } from 'ws-dottie'; // Runtime configuration for different environments function initializeApp(environment) { switch (environment) { case 'development': configManager.setConfig({ WSDOT_ACCESS_TOKEN: process.env.DEV_WSDOT_ACCESS_TOKEN, WSDOT_BASE_URL: 'https://dev-proxy.example.com' }); break; case 'production': configManager.setConfig({ WSDOT_ACCESS_TOKEN: process.env.PROD_WSDOT_ACCESS_TOKEN, WSDOT_BASE_URL: 'https://prod-proxy.example.com' }); break; } } // Use in your application initializeApp(process.env.NODE_ENV); const vessels = await WsfVessels.getVesselLocations(); ``` ### Parameter Objects and Logging ```javascript import { WsdotHighwayCameras, WsfFares, WsdotApiError } from 'ws-dottie'; async function getDetailedData() { try { // Get specific camera with logging const camera = await WsdotHighwayCameras.getCamera( { cameraID: 1001 }, 'debug' ); // Get fare information with parameters const fares = await WsfFares.getFareLineItems({ tripDate: new Date('2024-01-15'), departingTerminalID: 7, arrivingTerminalID: 8, roundTrip: false }, 'info'); // Search cameras with filters const cameras = await WsdotHighwayCameras.searchCameras({ StateRoute: "5", Region: "Northwest" }); return { camera, fares, cameras }; } catch (error) { if (error instanceof WsdotApiError) { console.error('Error:', error.getUserMessage()); } throw error; } } ``` ### Error Boundary Integration ```javascript import { WsdotApiError } from 'ws-dottie'; class WSdotErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { if (error instanceof WsdotApiError) { return { hasError: true, error }; } return { hasError: false }; } render() { if (this.state.hasError) { return ( <div className="error-boundary"> <h2>Transportation Data Error</h2> <p>{this.state.error.getUserMessage()}</p> <button onClick={() => this.setState({ hasError: false })}> Try Again </button> </div> ); } return this.props.children; } } function App() { return ( <WSdotErrorBoundary> <QueryClientProvider client={queryClient}> <TransportationDashboard /> </QueryClientProvider> </WSdotErrorBoundary> ); } ``` ### Custom Loading States ```javascript import { useVesselLocations } from 'ws-dottie'; function VesselList() { const { data: vessels, isLoading, isFetching, error } = useVesselLocations(); if (isLoading) { return <div className="loading">Loading vessels...</div>; } if (error) { return <div className="error">Error loading vessels: {error.getUserMessage()}</div>; } return ( <div> <h2>Vessels ({vessels?.length || 0})</h2> {isFetching && <div className="refreshing">Refreshing...</div>} {vessels?.map(vessel => ( <div key={vessel.VesselID} className="vessel"> <h3>{vessel.VesselName}</h3> <p>Location: {vessel.Latitude}, {vessel.Longitude}</p> </div> ))} </div> ); } ``` ### Custom Caching Configuration ```javascript import { useVesselLocations, tanstackQueryOptions } from 'ws-dottie'; function CustomVesselTracker() { // Use custom caching for more frequent updates const { data: vessels } = useVesselLocations({ ...tanstackQueryOptions.REALTIME_UPDATES, refetchInterval: 2000, // Update every 2 seconds staleTime: 1000, // Consider data stale after 1 second }); return ( <div> <h2>Real-time Vessel Tracking</h2> {vessels?.map(vessel => ( <div key={vessel.VesselID}> <strong>{vessel.VesselName}</strong> <div>Last Update: {vessel.LastUpdate.toLocaleTimeString()}</div> </div> ))} </div> ); } ``` ### Advanced Caching Customization WS-Dottie's caching strategies can be customized using spread operators with TanStack Query options: ```javascript import { useVesselLocations, tanstackQueryOptions } from 'ws-dottie'; function AdvancedVesselTracker() { // Custom 5-minute update strategy with different parameters const { data: vessels } = useVesselLocations({ ...tanstackQueryOptions.REALTIME_UPDATES, // Start with real-time base refetchInterval: 5 * 60 * 1000, // 5 minutes staleTime: 2 * 60 * 1000, // 2 minutes gcTime: 60 * 60 * 1000, // 1 hour retry: 3, // 3 retries retryDelay: 5 * 1000, // 5 second delay between retries }); return ( <div> <h2>Vessels (5-minute updates)</h2> {vessels?.map(vessel => ( <div key={vessel.VesselID}> <strong>{vessel.VesselName}</strong> <div>Last Update: {vessel.LastUpdate.toLocaleTimeString()}</div> </div> ))} </div> ); } ``` This approach allows you to: - **Extend base strategies** - Start with a predefined strategy and customize specific options - **Mix and match** - Combine different aspects of various strategies - **Fine-tune performance** - Optimize caching for your specific use case - **Maintain consistency** - Keep the base strategy's proven defaults while customizing only what you need ### Multiple API Integration ```javascript import { useVesselLocations, useTerminalWaitTimes, useHighwayAlerts, useTrafficFlows } from 'ws-dottie'; function ComprehensiveDashboard() { const { data: vessels } = useVesselLocations(); const { data: waitTimes } = useTerminalWaitTimes(); const { data: alerts } = useHighwayAlerts(); const { data: flows } = useTrafficFlows(); const isLoading = !vessels || !waitTimes || !alerts || !flows; if (isLoading) { return <div>Loading comprehensive data...</div>; } return ( <div className="dashboard"> <div className="section"> <h2>Ferry System</h2> <div>Active Vessels: {vessels.length}</div> <div>Terminals with Wait Times: {waitTimes.length}</div> </div> <div className="section"> <h2>Highway System</h2> <div>Active Alerts: {alerts.length}</div> <div>Traffic Flow Stations: {flows.length}</div> </div> </div> ); } ``` ## 🎯 Real-World Project Examples ### Ferry Commuter App ```javascript import { useVesselLocations, useTerminalWaitTimes, useSchedules } from 'ws-dottie'; function FerryCommuterApp() { const { data: vessels } = useVesselLocations(); const { data: waitTimes } = useTerminalWaitTimes(); const { data: schedules } = useSchedules({ routeId: 1 }); const myTerminal = waitTimes?.find(t => t.TerminalName === 'Seattle'); const nextFerry = schedules?.find(s => s.DepartureTime > new Date()); return ( <div className="commuter-app"> <h1>Ferry Commuter</h1> {myTerminal && ( <div className="wait-time"> <h2>Seattle Terminal</h2> <div className="wait">Wait Time: {myTerminal.WaitTime} minutes</div> </div> )} {nextFerry && ( <div className="next-ferry"> <h2>Next Ferry</h2> <div>Departure: {nextFerry.DepartureTime.toLocaleTimeString()}</div> </div> )} <div className="vessel-map"> <h2>Active Vessels ({vessels?.length || 0})</h2> {/* Render vessel locations on a map */} </div> </div> ); } ``` ### Traffic Camera Viewer ```javascript import { useHighwayCameras, useSearchHighwayCameras } from 'ws-dottie'; function TrafficCameraViewer() { const [selectedRoute, setSelectedRoute] = useState('5'); const { data: allCameras } = useHighwayCameras(); const { data: routeCameras } = useSearchHighwayCameras({ StateRoute: selectedRoute }); return ( <div className="camera-viewer"> <h1>Traffic Cameras</h1> <div className="filters"> <select value={selectedRoute} onChange={e => setSelectedRoute(e.target.value)}> <option value="5">I-5</option> <option value="405">I-405</option> <option value="90">I-90</option> </select> </div> <div className="camera-grid"> {routeCameras?.map(camera => ( <div key={camera.CameraID} className="camera"> <h3>{camera.Title}</h3> <img src={camera.ImageURL} alt={camera.Title} /> <div>Location: {camera.RoadName}</div> </div> ))} </div> </div> ); } ``` ### Weather Dashboard ```javascript import { useWeatherStations, useMountainPassConditions, useWeatherInformationForStations } from 'ws-dottie'; function WeatherDashboard() { const { data: stations } = useWeatherStations(); const { data: passes } = useMountainPassConditions(); const { data: weather } = useWeatherInformationForStations({ stationIds: [1, 2, 3, 4, 5] }); const seattleStation = stations?.find(s => s.StationName.includes('Seattle')); const snoqualmiePass = passes?.find(p => p.MountainPassName.includes('Snoqualmie')); return ( <div className="weather-dashboard"> <h1>Washington Weather</h1> {seattleStation && ( <div className="current-weather"> <h2>Seattle</h2> <div>Temperature: {seattleStation.Temperature}°F</div> <div>Conditions: {seattleStation.RoadCondition}</div> </div> )} {snoqualmiePass && ( <div className="pass-conditions"> <h2>Snoqualmie Pass</h2> <div>Status: {snoqualmiePass.RestrictionOne}</div> <div>Conditions: {snoqualmiePass.RoadCondition}</div> </div> )} <div className="weather-stations"> <h2>Weather Stations ({stations?.length || 0})</h2> {/* Render weather station data */} </div> </div> ); } ``` ## 🚨 Troubleshooting ### Common Issues **"API key not found" error** ```javascript // Check your environment variables console.log('WSDOT_ACCESS_TOKEN:', process.env.WSDOT_ACCESS_TOKEN); ``` **"QueryClient not found" error** ```