@drfrost/bods-js
Version:
JavaScript client for the UK's Bus Open Data Service (BODS) API
161 lines (160 loc) • 6.05 kB
JavaScript
/**
* Client for interacting with the BODS Disruptions API
*
* The Disruptions API provides information about current and planned
* disruptions to bus services in SIRI-SX format (XML).
* Data is updated as new information becomes available.
*/
export class DisruptionsClient {
constructor(httpClient) {
this.httpClient = httpClient;
}
/**
* Get all current service disruptions in SIRI-SX format
*
* @returns Promise resolving to SIRI-SX XML data containing all disruptions
*
* @example
* ```typescript
* // Get all current disruptions
* const disruptions = await client.disruptions.getAll();
* console.log('Disruptions XML:', disruptions.xmlData);
*
* // You would typically parse the XML to extract specific disruption details
* const parser = new DOMParser();
* const doc = parser.parseFromString(disruptions.xmlData, 'text/xml');
* ```
*/
async getAll() {
const response = await this.httpClient.get('/api/v1/siri-sx');
return { xmlData: response.data };
}
/**
* Get current service disruptions (alias for getAll)
*
* @returns Promise resolving to SIRI-SX XML data containing current disruptions
*
* @example
* ```typescript
* const currentDisruptions = await client.disruptions.getCurrent();
* ```
*/
async getCurrent() {
return this.getAll();
}
/**
* Helper method to parse SIRI-SX XML and extract basic disruption information
* Note: This is a basic parser. For production use, consider a more robust XML parsing solution.
* Requires a DOM environment (browser) or a polyfill like jsdom in Node.js.
*
* @param xmlData - Raw SIRI-SX XML data
* @returns Array of parsed disruption objects
*
* @example
* ```typescript
* const disruptions = await client.disruptions.getAll();
* const parsed = client.disruptions.parseDisruptions(disruptions.xmlData);
*
* parsed.forEach(disruption => {
* console.log(`${disruption.summary}: ${disruption.description}`);
* });
* ```
*/
parseDisruptions(xmlData) {
try {
// Check if DOMParser is available (browser environment)
if (typeof DOMParser === 'undefined') {
console.warn('DOMParser not available. XML parsing requires a DOM environment or polyfill.');
return [];
}
const parser = new DOMParser();
const doc = parser.parseFromString(xmlData, 'text/xml');
const situations = doc.querySelectorAll('PtSituationElement');
const results = [];
situations.forEach((situation) => {
const situationNumber = situation.querySelector('SituationNumber')?.textContent || undefined;
const participantRef = situation.querySelector('ParticipantRef')?.textContent || undefined;
const summary = situation.querySelector('Summary')?.textContent || undefined;
const description = situation.querySelector('Description')?.textContent || undefined;
const severity = situation.querySelector('Severity')?.textContent || undefined;
const startTime = situation.querySelector('ValidityPeriod StartTime')?.textContent || undefined;
const endTime = situation.querySelector('ValidityPeriod EndTime')?.textContent || undefined;
const plannedText = situation.querySelector('Planned')?.textContent;
const planned = plannedText ? plannedText.toLowerCase() === 'true' : undefined;
results.push({
situationNumber,
participantRef,
summary,
description,
severity,
startTime,
endTime,
planned
});
});
return results;
}
catch (error) {
console.warn('Failed to parse SIRI-SX XML:', error);
return [];
}
}
/**
* Get and parse current disruptions in one call
*
* @returns Promise resolving to array of parsed disruption objects
*
* @example
* ```typescript
* const disruptions = await client.disruptions.getCurrentParsed();
*
* disruptions.forEach(disruption => {
* if (disruption.planned) {
* console.log(`Planned disruption: ${disruption.summary}`);
* } else {
* console.log(`Unplanned disruption: ${disruption.summary}`);
* }
* });
* ```
*/
async getCurrentParsed() {
const disruptions = await this.getAll();
return this.parseDisruptions(disruptions.xmlData);
}
/**
* Filter parsed disruptions by criteria
*
* @param disruptions - Array of parsed disruptions
* @param filters - Filter criteria
* @returns Filtered array of disruptions
*
* @example
* ```typescript
* const allDisruptions = await client.disruptions.getCurrentParsed();
*
* // Get only unplanned disruptions
* const unplanned = client.disruptions.filterDisruptions(allDisruptions, {
* planned: false
* });
*
* // Get disruptions from specific participant
* const tfgmDisruptions = client.disruptions.filterDisruptions(allDisruptions, {
* participantRef: 'TfGM'
* });
* ```
*/
filterDisruptions(disruptions, filters) {
return disruptions.filter(disruption => {
if (filters.planned !== undefined && disruption.planned !== filters.planned) {
return false;
}
if (filters.participantRef && disruption.participantRef !== filters.participantRef) {
return false;
}
if (filters.severity && disruption.severity !== filters.severity) {
return false;
}
return true;
});
}
}