UNPKG

@drfrost/bods-js

Version:

JavaScript client for the UK's Bus Open Data Service (BODS) API

244 lines (211 loc) • 7.82 kB
/** * Example usage of the BODS JavaScript Client * * This file demonstrates various ways to use the BODS API client * to access UK bus data including timetables, fares, real-time locations, * and service disruptions. */ import { BODSClient, createBoundingBox, UK_CITIES } from './index.js'; /** * Initialize the BODS client with your API key * Get your API key from: https://data.bus-data.dft.gov.uk/account/ */ const client = new BODSClient({ apiKey: 'your-api-key-here', // Replace with your actual API key timeout: 30000 // Optional: 30 second timeout }); /** * Example 1: Search for timetables */ async function searchTimetables() { try { // Find all published timetables for Stagecoach Manchester const timetables = await client.timetables.search({ noc: ['SCMN'], // Stagecoach Manchester status: 'published', limit: 10 }); console.log(`Found ${timetables.count} timetables`); timetables.results.forEach(timetable => { console.log(`- ${timetable.operatorName}: ${timetable.name}`); console.log(` Lines: ${timetable.lines.join(', ')}`); console.log(` Quality: ${timetable.dqRag} (${timetable.dqScore})`); }); // Get a specific timetable by ID if (timetables.results.length > 0) { const firstTimetable = await client.timetables.getById(timetables.results[0]!.id); console.log('Detailed timetable:', firstTimetable); } } catch (error) { console.error('Error fetching timetables:', error); } } /** * Example 2: Search for fares by geographic area */ async function searchFaresByArea() { try { // Get fares for the Manchester area const manchesterBox = UK_CITIES.MANCHESTER; const fares = await client.fares.getByArea(manchesterBox); console.log(`Found ${fares.count} fare datasets in Manchester area`); fares.results.forEach(fare => { console.log(`- ${fare.operatorName}: ${fare.name}`); console.log(` Fare zones: ${fare.numOfFareZones}`); console.log(` Products: ${fare.numOfFareProducts}`); }); // Create custom bounding box for Liverpool city center (5km radius) const liverpoolBox = createBoundingBox(53.4084, -2.9916, 5); const liverpoolFares = await client.fares.getByArea(liverpoolBox); console.log(`Liverpool fares: ${liverpoolFares.count}`); } catch (error) { console.error('Error fetching fares:', error); } } /** * Example 3: Get real-time vehicle locations */ async function getVehicleLocations() { try { // Get real-time locations for specific operators in SIRI-VM format const vehicles = await client.avl.getSIRIVM({ operatorRef: ['SCMN', 'SCGH'], // Stagecoach operators boundingBox: UK_CITIES.MANCHESTER }); console.log('Vehicle locations (SIRI-VM XML):'); console.log(vehicles.xmlData.substring(0, 500) + '...'); // Get vehicles for a specific bus line const lineVehicles = await client.avl.getByLine('85A'); console.log('Line 85A vehicles:', lineVehicles.xmlData.length > 0 ? 'Data received' : 'No data'); // Get vehicles in GTFS-RT format (binary protobuf) const gtfsVehicles = await client.avl.getGTFSRT({ boundingBox: createBoundingBox(53.4808, -2.2426, 10) // Manchester, 10km radius }); console.log('GTFS-RT data size:', gtfsVehicles.protobufData.byteLength, 'bytes'); } catch (error) { console.error('Error fetching vehicle locations:', error); } } /** * Example 4: Get service disruptions */ async function getDisruptions() { try { // Get all current disruptions const disruptions = await client.disruptions.getCurrent(); console.log('Raw disruptions XML length:', disruptions.xmlData.length); // Parse disruptions to extract useful information const parsed = await client.disruptions.getCurrentParsed(); console.log(`Found ${parsed.length} parsed disruptions`); parsed.forEach(disruption => { console.log(`\n${disruption.planned ? 'PLANNED' : 'UNPLANNED'} DISRUPTION:`); console.log(`Summary: ${disruption.summary}`); console.log(`Authority: ${disruption.participantRef}`); console.log(`Severity: ${disruption.severity}`); if (disruption.startTime) { console.log(`Start: ${new Date(disruption.startTime).toLocaleString()}`); } if (disruption.description) { console.log(`Description: ${disruption.description.substring(0, 100)}...`); } }); // Filter for unplanned disruptions only const unplanned = client.disruptions.filterDisruptions(parsed, { planned: false }); console.log(`\nUnplanned disruptions: ${unplanned.length}`); } catch (error) { console.error('Error fetching disruptions:', error); } } /** * Example 5: Advanced searches and filtering */ async function advancedExamples() { try { // Get high-quality, BODS-compliant timetables const qualityTimetables = await client.timetables.getHighQuality({ bodsCompliance: true, adminArea: ['060'] // Cheshire East }); console.log(`High-quality timetables in Cheshire East: ${qualityTimetables.count}`); // Get recently modified timetables (last 7 days) const lastWeek = new Date(); lastWeek.setDate(lastWeek.getDate() - 7); const recentTimetables = await client.timetables.getRecentlyModified(lastWeek); console.log(`Recently modified timetables: ${recentTimetables.count}`); // Get published fares only const publishedFares = await client.fares.getPublished({ noc: ['SCMN'], limit: 5 }); console.log(`Published Stagecoach Manchester fares: ${publishedFares.count}`); // Test API connectivity const isConnected = await client.testConnection(); console.log(`API connection test: ${isConnected ? 'SUCCESS' : 'FAILED'}`); } catch (error) { console.error('Error in advanced examples:', error); } } /** * Example 6: Error handling and validation */ async function errorHandlingExample() { try { // This will fail if API key is invalid await client.timetables.search({ limit: 1 }); console.log('API key is valid'); } catch (error) { if (error instanceof Error) { console.error('API Error:', error.message); // Check if it's an HTTP error with specific status if ('status' in error) { const httpError = error as any; switch (httpError.status) { case 401: console.error('Unauthorized - check your API key'); break; case 403: console.error('Forbidden - API key may not have required permissions'); break; case 429: console.error('Rate limited - too many requests'); break; default: console.error(`HTTP ${httpError.status}: ${httpError.message}`); } } } } } /** * Run all examples */ async function runAllExamples() { console.log('🚌 BODS JavaScript Client Examples\n'); console.log('='.repeat(50)); console.log('\nšŸ“… Example 1: Timetables'); await searchTimetables(); console.log('\nšŸŽŸļø Example 2: Fares by Area'); await searchFaresByArea(); console.log('\n🚌 Example 3: Real-time Vehicle Locations'); await getVehicleLocations(); console.log('\nāš ļø Example 4: Service Disruptions'); await getDisruptions(); console.log('\nšŸ” Example 5: Advanced Searches'); await advancedExamples(); console.log('\nāŒ Example 6: Error Handling'); await errorHandlingExample(); console.log('\nāœ… Examples completed!'); } // Run examples if this file is executed directly if (import.meta.main) { runAllExamples().catch(console.error); } export { searchTimetables, searchFaresByArea, getVehicleLocations, getDisruptions, advancedExamples, errorHandlingExample, runAllExamples };