const express = require("express"); const axios = require("axios"); const config = require("../config/api"); const router = express.Router(); router.get("/", async (req, res) => { try { const { apiKey, baseUrl, city, units, language } = config.weather; if (!apiKey) { return res.status(400).json({ message: "OPENWEATHER_API_KEY is not set" }); } const { q, lat, lon } = req.query; const params = { appid: apiKey, units, lang: language, }; let currentResponse, forecastResponse, airResponse; if (lat && lon) { // 1. Parallel fetch for all 3 endpoints if coordinates are available [currentResponse, forecastResponse, airResponse] = await Promise.all([ axios.get(`${baseUrl}/weather`, { params: { ...params, lat, lon } }), axios.get(`${baseUrl}/forecast`, { params: { ...params, lat, lon } }), axios.get(`${baseUrl}/air_pollution`, { params: { lat, lon, appid: apiKey } }), ]); } else { // 2. Sequential fallback if only city name is provided params.q = q || city; currentResponse = await axios.get(`${baseUrl}/weather`, { params }); const { coord } = currentResponse.data; [forecastResponse, airResponse] = await Promise.all([ axios.get(`${baseUrl}/forecast`, { params: { ...params, lat: coord.lat, lon: coord.lon }, }), axios.get(`${baseUrl}/air_pollution`, { params: { lat: coord.lat, lon: coord.lon, appid: apiKey }, }), ]); } const currentData = currentResponse.data; // 3. Process Forecast for Today's Min/Max (Seoul Time: UTC+9) // OpenWeatherMap returns timestamps in UTC. // Seoul is UTC+9. const SeoulOffset = 9 * 60 * 60 * 1000; const nowKST = new Date(Date.now() + SeoulOffset); const todayStr = nowKST.toISOString().split("T")[0]; // YYYY-MM-DD in KST const todayItems = forecastResponse.data.list.filter((item) => { const itemDateKST = new Date(item.dt * 1000 + SeoulOffset); const itemDateStr = itemDateKST.toISOString().split("T")[0]; return itemDateStr === todayStr; }); if (todayItems.length > 0) { // Find min and max from the 3-hour segments const minTemp = Math.min(...todayItems.map((item) => item.main.temp_min)); const maxTemp = Math.max(...todayItems.map((item) => item.main.temp_max)); // Update the response structure currentData.main.temp_min = minTemp; currentData.main.temp_max = maxTemp; } // 4. Attach Air Quality (AQI) // OpenWeatherMap AQI: 1 (Good) ... 5 (Very Poor) if (airResponse.data.list && airResponse.data.list.length > 0) { currentData.aqi = airResponse.data.list[0].main.aqi; } res.json(currentData); } catch (error) { console.error("Weather API Error:", error.message); if (error.response) { console.error("Data:", error.response.data); } res.status(500).json({ message: "Failed to fetch weather" }); } }); module.exports = router;