Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/api/routes/weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from fastapi import APIRouter, Query
from fastapi.exceptions import RequestValidationError
from openmeteo_requests.Client import OpenMeteoRequestsError

from app.core.errors.base import AppError
from app.services.external_apis.weather_api import WeatherAPI
Expand Down Expand Up @@ -55,5 +56,8 @@ def get_weather_forecast(
latitude, longitude, start_date.isoformat(), end_date.isoformat(), hourly_fields=requested
)
return weather_data
except OpenMeteoRequestsError as e:
# Open-Meteo failed or was unreachable: the failure is upstream, not ours
raise AppError(str(e), status_code=502, error_code="WEATHER_FETCH_FAILED")
except Exception as e:
raise AppError(str(e), status_code=500)
23 changes: 23 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,29 @@ def fake_get_weather(self, latitude, longitude, start_date, end_date, hourly_fie
"end_date": "2026-10-20",
}

def test_forecast_upstream_error_is_502(self, client, monkeypatch):
from openmeteo_requests.Client import OpenMeteoRequestsError

def fake_weather_api(*args, **kwargs):
raise OpenMeteoRequestsError("failed to request 'https://api.open-meteo.com/v1/forecast': offline")

monkeypatch.setattr("openmeteo_requests.Client.weather_api", fake_weather_api)

resp = client.get(self.WEATHER_URL, params=self.VALID)
assert resp.status_code == 502
body = resp.json()
assert body["error_code"] == "WEATHER_FETCH_FAILED"
assert "offline" in body["message"]

def test_forecast_unexpected_error_is_500(self, client, monkeypatch):
def fake_get_weather(*args, **kwargs):
raise ValueError("boom")

monkeypatch.setattr("app.api.routes.weather.WeatherAPI.get_weather", fake_get_weather)

resp = client.get(self.WEATHER_URL, params=self.VALID)
assert resp.status_code == 500

@pytest.mark.parametrize(
"overrides, field",
[
Expand Down
Loading