Files
FarmaFinder/API/open-data.js
2026-04-01 01:18:21 +02:00

117 lines
3.5 KiB
JavaScript

/**
* Load pharmacy rows from a public open-data URL (JSON array, GeoJSON, or similar).
* No default URL — pass the dataset URL from the client (regional open-data portals).
*/
function rowsFromGeoJson(json) {
if (!json || json.type !== 'FeatureCollection' || !Array.isArray(json.features)) {
return [];
}
return json.features
.map((f) => {
const p = f.properties || {};
const name = p.name || p.nombre || p.denominacion || p.title;
const address =
p.address ||
p.direccion ||
p.domicilio ||
[p.calle, p.municipio, p.codigo_postal].filter(Boolean).join(', ');
let lat;
let lon;
if (f.geometry?.type === 'Point' && Array.isArray(f.geometry.coordinates)) {
lon = f.geometry.coordinates[0];
lat = f.geometry.coordinates[1];
}
return {
name: name ? String(name).trim() : null,
address: address ? String(address).trim() : null,
phone: p.phone || p.telefono || p.tel || null,
latitude: lat != null ? Number(lat) : null,
longitude: lon != null ? Number(lon) : null,
};
})
.filter((r) => r.name && r.address);
}
function rowsFromJsonArray(json) {
if (!Array.isArray(json)) return [];
return json
.map((row) => {
if (!row || typeof row !== 'object') return null;
const name = row.name || row.nombre || row.farmacia;
const address =
row.address ||
row.direccion ||
row.domicilio ||
row.full_address;
return {
name: name ? String(name).trim() : null,
address: address ? String(address).trim() : null,
phone: row.phone || row.telefono || null,
latitude:
row.latitude != null
? Number(row.latitude)
: row.lat != null
? Number(row.lat)
: null,
longitude:
row.longitude != null
? Number(row.longitude)
: row.lon != null
? Number(row.lon)
: row.lng != null
? Number(row.lng)
: null,
};
})
.filter((r) => r && r.name && r.address);
}
/**
* @param {string} openDataUrl - HTTPS URL returning JSON
* @returns {Promise<Array<{name,address,phone,latitude,longitude}>>}
*/
export async function fetchPharmaciesFromOpenDataUrl(openDataUrl) {
if (!openDataUrl || typeof openDataUrl !== 'string' || !openDataUrl.trim()) {
throw new Error('openData source requires a non-empty openDataUrl');
}
const u = openDataUrl.trim();
if (!/^https?:\/\//i.test(u)) {
throw new Error('openDataUrl must be an http(s) URL');
}
const res = await fetch(u, {
headers: {
Accept: 'application/json',
'User-Agent': 'FarmaFinder/1.0 (open-data pharmacy import)',
},
});
const text = await res.text();
if (!res.ok) {
throw new Error(`Open data HTTP ${res.status}: ${text.slice(0, 120)}`);
}
let json;
try {
json = text ? JSON.parse(text) : null;
} catch {
throw new Error('Open data response is not JSON');
}
if (json && json.type === 'FeatureCollection') {
return rowsFromGeoJson(json);
}
if (Array.isArray(json)) {
return rowsFromJsonArray(json);
}
if (json && Array.isArray(json.data)) {
return rowsFromJsonArray(json.data);
}
if (json && Array.isArray(json.records)) {
return rowsFromJsonArray(json.records);
}
throw new Error(
'Unsupported open-data JSON shape (expected FeatureCollection, array, or { data: [] })'
);
}