68 lines
2.6 KiB
JavaScript
68 lines
2.6 KiB
JavaScript
const axios = require('axios');
|
|
const logger = require('../utils/logger');
|
|
|
|
const SOCRATA_DOMAIN = 'https://data.edmonton.ca';
|
|
|
|
class SocrataService {
|
|
constructor() {
|
|
this.client = axios.create({
|
|
baseURL: SOCRATA_DOMAIN,
|
|
timeout: 30000 // 30 seconds for potentially large datasets
|
|
});
|
|
|
|
this.client.interceptors.response.use(
|
|
response => response,
|
|
error => {
|
|
logger.error('Socrata API Error:', {
|
|
message: error.message,
|
|
url: error.config?.url,
|
|
status: error.response?.status,
|
|
data: error.response?.data
|
|
});
|
|
throw error;
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Fetches data from a Socrata dataset.
|
|
* @param {string} datasetId - The ID of the dataset (e.g., 'nggt-rwac').
|
|
* @param {object} params - SoQL query parameters.
|
|
* @returns {Promise<Array>} A promise that resolves to an array of records.
|
|
*/
|
|
async get(datasetId, params = {}) {
|
|
try {
|
|
logger.info(`Fetching Socrata dataset ${datasetId} with params:`, params);
|
|
|
|
// Socrata uses an app token for higher rate limits, but it's not required for public data.
|
|
// We can add an X-App-Token header here if one is obtained.
|
|
const response = await this.client.get(`/resource/${datasetId}.json`, { params });
|
|
|
|
logger.info(`Successfully fetched ${response.data.length} records from Socrata dataset ${datasetId}`);
|
|
return response.data;
|
|
} catch (error) {
|
|
logger.error(`Failed to fetch Socrata dataset ${datasetId}`, {
|
|
message: error.message,
|
|
status: error.response?.status,
|
|
statusText: error.response?.statusText,
|
|
data: error.response?.data,
|
|
url: error.config?.url,
|
|
params: params
|
|
});
|
|
|
|
// Provide more specific error messages
|
|
if (error.response?.status === 404) {
|
|
throw new Error(`Dataset ${datasetId} not found on Socrata API`);
|
|
} else if (error.response?.status === 400) {
|
|
throw new Error(`Invalid query parameters for dataset ${datasetId}`);
|
|
} else if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
|
|
throw new Error('Unable to connect to Edmonton Open Data Portal');
|
|
}
|
|
|
|
throw new Error('Could not retrieve data from the external source.');
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new SocrataService();
|