REFACTOR data service
This commit is contained in:
264
frontend/src/api/services/external.service.ts
Normal file
264
frontend/src/api/services/external.service.ts
Normal file
@@ -0,0 +1,264 @@
|
||||
// frontend/src/api/services/external.service.ts
|
||||
/**
|
||||
* External Data Service
|
||||
* Handles weather and traffic data operations for the external microservice
|
||||
*/
|
||||
|
||||
import { apiClient } from '../client';
|
||||
import { RequestTimeouts } from '../client/config';
|
||||
|
||||
// Align with backend WeatherDataResponse schema
|
||||
export interface WeatherData {
|
||||
date: string;
|
||||
temperature?: number;
|
||||
precipitation?: number;
|
||||
humidity?: number;
|
||||
wind_speed?: number;
|
||||
pressure?: number;
|
||||
description?: string;
|
||||
source: string;
|
||||
}
|
||||
|
||||
// Align with backend TrafficDataResponse schema
|
||||
export interface TrafficData {
|
||||
date: string;
|
||||
traffic_volume?: number;
|
||||
pedestrian_count?: number;
|
||||
congestion_level?: string;
|
||||
average_speed?: number;
|
||||
source: string;
|
||||
}
|
||||
|
||||
export interface WeatherForecast {
|
||||
date: string;
|
||||
temperature_min: number;
|
||||
temperature_max: number;
|
||||
temperature_avg: number;
|
||||
precipitation: number;
|
||||
description: string;
|
||||
humidity?: number;
|
||||
wind_speed?: number;
|
||||
}
|
||||
|
||||
export class ExternalService {
|
||||
/**
|
||||
* Get Current Weather Data
|
||||
*/
|
||||
async getCurrentWeather(
|
||||
tenantId: string,
|
||||
lat: number,
|
||||
lon: number
|
||||
): Promise<WeatherData> {
|
||||
try {
|
||||
// ✅ FIX 1: Correct endpoint path with tenant ID
|
||||
const endpoint = `/tenants/${tenantId}/weather/current`;
|
||||
|
||||
// ✅ FIX 2: Correct parameter names (latitude/longitude, not lat/lon)
|
||||
const response = await apiClient.get(endpoint, {
|
||||
params: {
|
||||
latitude: lat, // Backend expects 'latitude'
|
||||
longitude: lon // Backend expects 'longitude'
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Weather API response:', response);
|
||||
|
||||
// Return backend response directly (matches WeatherData interface)
|
||||
return response;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch weather from backend:', error);
|
||||
|
||||
// Fallback weather for Madrid (matching WeatherData schema)
|
||||
return {
|
||||
date: new Date().toISOString(),
|
||||
temperature: 18,
|
||||
description: 'Parcialmente nublado',
|
||||
precipitation: 0,
|
||||
humidity: 65,
|
||||
wind_speed: 10,
|
||||
source: 'fallback'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Weather Forecast
|
||||
*/
|
||||
async getWeatherForecast(
|
||||
tenantId: string,
|
||||
lat: number,
|
||||
lon: number,
|
||||
days: number = 7
|
||||
): Promise<WeatherForecast[]> {
|
||||
try {
|
||||
// Fix: Use POST with JSON body as expected by backend
|
||||
const response = await apiClient.post(`/tenants/${tenantId}/weather/forecast`, {
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
days: days
|
||||
});
|
||||
|
||||
// Handle response format
|
||||
if (Array.isArray(response)) {
|
||||
return response;
|
||||
} else if (response && response.forecasts) {
|
||||
return response.forecasts;
|
||||
} else {
|
||||
console.warn('Unexpected weather forecast response format:', response);
|
||||
return [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch weather forecast:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Historical Weather Data
|
||||
*/
|
||||
async getHistoricalWeather(
|
||||
tenantId: string,
|
||||
lat: number,
|
||||
lon: number,
|
||||
startDate: string,
|
||||
endDate: string
|
||||
): Promise<WeatherData[]> {
|
||||
try {
|
||||
// Fix: Use POST with JSON body as expected by backend
|
||||
const response = await apiClient.post(`/tenants/${tenantId}/weather/historical`, {
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
start_date: startDate,
|
||||
end_date: endDate
|
||||
});
|
||||
|
||||
// Return backend response directly (matches WeatherData interface)
|
||||
return Array.isArray(response) ? response : response.data || [];
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch historical weather:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Current Traffic Data
|
||||
*/
|
||||
async getCurrentTraffic(
|
||||
tenantId: string,
|
||||
lat: number,
|
||||
lon: number
|
||||
): Promise<TrafficData> {
|
||||
try {
|
||||
const response = await apiClient.get(`/tenants/${tenantId}/traffic/current`, {
|
||||
params: {
|
||||
latitude: lat,
|
||||
longitude: lon
|
||||
}
|
||||
});
|
||||
|
||||
// Return backend response directly (matches TrafficData interface)
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch traffic data:', error);
|
||||
|
||||
// Fallback traffic data (matching TrafficData schema)
|
||||
return {
|
||||
date: new Date().toISOString(),
|
||||
traffic_volume: 50,
|
||||
pedestrian_count: 25,
|
||||
congestion_level: 'medium',
|
||||
average_speed: 30,
|
||||
source: 'fallback'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Traffic Forecast
|
||||
*/
|
||||
async getTrafficForecast(
|
||||
tenantId: string,
|
||||
lat: number,
|
||||
lon: number,
|
||||
hours: number = 24
|
||||
): Promise<TrafficData[]> {
|
||||
try {
|
||||
// Fix: Use POST with JSON body as expected by backend
|
||||
const response = await apiClient.post(`/tenants/${tenantId}/traffic/forecast`, {
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
hours: hours
|
||||
});
|
||||
|
||||
// Return backend response directly (matches TrafficData interface)
|
||||
return Array.isArray(response) ? response : response.data || [];
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch traffic forecast:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Historical Traffic Data
|
||||
*/
|
||||
async getHistoricalTraffic(
|
||||
tenantId: string,
|
||||
lat: number,
|
||||
lon: number,
|
||||
startDate: string,
|
||||
endDate: string
|
||||
): Promise<TrafficData[]> {
|
||||
try {
|
||||
// Fix: Use POST with JSON body as expected by backend
|
||||
const response = await apiClient.post(`/tenants/${tenantId}/traffic/historical`, {
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
start_date: startDate,
|
||||
end_date: endDate
|
||||
});
|
||||
|
||||
// Return backend response directly (matches TrafficData interface)
|
||||
return Array.isArray(response) ? response : response.data || [];
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch historical traffic:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test External Service Connectivity
|
||||
*/
|
||||
async testConnectivity(tenantId: string): Promise<{
|
||||
weather: boolean;
|
||||
traffic: boolean;
|
||||
overall: boolean;
|
||||
}> {
|
||||
const results = {
|
||||
weather: false,
|
||||
traffic: false,
|
||||
overall: false
|
||||
};
|
||||
|
||||
try {
|
||||
// Test weather service
|
||||
await this.getCurrentWeather(tenantId, 40.4168, -3.7038); // Madrid coordinates
|
||||
results.weather = true;
|
||||
} catch (error) {
|
||||
console.warn('Weather service connectivity test failed:', error);
|
||||
}
|
||||
|
||||
try {
|
||||
// Test traffic service
|
||||
await this.getCurrentTraffic(tenantId, 40.4168, -3.7038); // Madrid coordinates
|
||||
results.traffic = true;
|
||||
} catch (error) {
|
||||
console.warn('Traffic service connectivity test failed:', error);
|
||||
}
|
||||
|
||||
results.overall = results.weather && results.traffic;
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
export const externalService = new ExternalService();
|
||||
Reference in New Issue
Block a user