Files
bakery-ia/frontend/src/api/services/external.service.ts
2025-08-18 20:50:41 +02:00

296 lines
8.4 KiB
TypeScript

// 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 interface HourlyForecast {
forecast_datetime: string;
generated_at: string;
temperature: number;
precipitation: number;
humidity: number;
wind_speed: number;
description: string;
source: string;
hour: 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 AEMET API via backend:', error);
throw new Error(`Weather data unavailable: ${error instanceof Error ? error.message : 'AEMET API connection failed'}`);
}
}
/**
* 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 from AEMET API:', error);
throw new Error(`Weather forecast unavailable: ${error instanceof Error ? error.message : 'AEMET API connection failed'}`);
}
}
/**
* Get Hourly Weather Forecast (NEW)
*/
async getHourlyWeatherForecast(
tenantId: string,
lat: number,
lon: number,
hours: number = 48
): Promise<HourlyForecast[]> {
try {
console.log(`🕒 Fetching hourly weather forecast from AEMET API for tenant ${tenantId}`, {
latitude: lat,
longitude: lon,
hours: hours
});
const response = await apiClient.post(`/tenants/${tenantId}/weather/hourly-forecast`, {
latitude: lat,
longitude: lon,
hours: hours
});
// Handle response format
if (Array.isArray(response)) {
return response;
} else if (response && response.data) {
return response.data;
} else {
console.warn('Unexpected hourly forecast response format:', response);
return [];
}
} catch (error) {
console.error('Failed to fetch hourly forecast from AEMET API:', error);
throw new Error(`Hourly forecast unavailable: ${error instanceof Error ? error.message : 'AEMET API connection failed'}`);
}
}
/**
* 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 from AEMET API:', error);
throw new Error(`Historical weather data unavailable: ${error instanceof Error ? error.message : 'AEMET API connection failed'}`);
}
}
/**
* 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 from external API:', error);
throw new Error(`Traffic data unavailable: ${error instanceof Error ? error.message : 'External API connection failed'}`);
}
}
/**
* 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 from external API:', error);
throw new Error(`Traffic forecast unavailable: ${error instanceof Error ? error.message : 'External API connection failed'}`);
}
}
/**
* 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 from external API:', error);
throw new Error(`Historical traffic data unavailable: ${error instanceof Error ? error.message : 'External API connection failed'}`);
}
}
/**
* 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 (AEMET API)
await this.getCurrentWeather(tenantId, 40.4168, -3.7038); // Madrid coordinates
results.weather = true;
} catch (error) {
console.warn('AEMET weather service connectivity test failed:', error);
results.weather = false;
}
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.traffic = false;
}
results.overall = results.weather && results.traffic;
return results;
}
}
export const externalService = new ExternalService();