class Services::Application::WeatherByAddress
Weather by address
Application service that orchestrates a single use case:
-
Geocodes the address (latitude, longitude, optional zipcode).
-
Fetches in parallel: current weather, hourly forecast, daily forecast.
-
Maps raw responses to domain objects via Acl (Anti-Corruption Layer).
-
Returns a Result wrapping a WeatherAtLocation domain aggregate plus data-source metadata (cache vs API) for each adapter call.
Dependencies (injected)
-
geocode_adapter —
call(address)→ response with lat/lng/zipcode. -
current_weather_adapter —
call(lat, lng, zipcode:)→ response. -
hourly_forecast_adapter —
call(lat, lng, zipcode:)→ response. -
daily_forecast_adapter —
call(lat, lng, zipcode:)→ response. -
acl — Anti-Corruption Layer that translates raw API data into domain value objects.
Errors
Infrastructure adapter errors are translated to application-layer errors so the presentation layer never depends on infrastructure details (DIP):
-
AddressNotFoundError— geocode found no results. -
WeatherNotFoundError— weather provider returned no data. -
ServiceError— any other adapter/network failure.
Example
service = Services::Application::WeatherByAddress.new result = service.call("São Paulo, Brazil") result.location.latitude # => -23.55 result.current_weather.temperature_degrees # => 25.3 result.from_cache?(:geocode) # => false
Nested constants (defined in weather_by_address/)
-
WeatherByAddress::Acl— Anti-Corruption Layer that shields the domain from external API data structures. -
WeatherByAddress::Result— Immutable wrapper that delegates weather fields to WeatherAtLocation and tracks per-adapter data sources.
Public Class Methods
Source
# File app/services/application/weather_by_address.rb 49 def initialize( 50 geocode_adapter: default_geocode_adapter, 51 current_weather_adapter: default_current_weather_adapter, 52 hourly_forecast_adapter: default_hourly_forecast_adapter, 53 daily_forecast_adapter: default_daily_forecast_adapter, 54 acl: Acl.new 55 ) 56 @geocode_adapter = geocode_adapter 57 @current_weather_adapter = current_weather_adapter 58 @hourly_forecast_adapter = hourly_forecast_adapter 59 @daily_forecast_adapter = daily_forecast_adapter 60 @acl = acl 61 end
Public Instance Methods
Source
# File app/services/application/weather_by_address.rb 66 def call(address) 67 geocode_response = @geocode_adapter.call(address.to_s.strip) 68 location = @acl.build_location(geocode_response) 69 70 current_resp, hourly_resp, daily_resp = 71 fetch_weather_in_parallel(location.latitude, location.longitude, location.zipcode) 72 73 weather = Domains::Weather::WeatherAtLocation.new( 74 location: location, 75 current_weather: @acl.build_current_weather(current_resp.data), 76 hourly_forecast_entries: @acl.build_hourly_forecast_entries(hourly_resp.data), 77 daily_forecast_entries: @acl.build_daily_forecast_entries(daily_resp.data) 78 ) 79 80 Result.new( 81 weather_at_location: weather, 82 sources: { 83 geocode: geocode_response.source, 84 current_weather: current_resp.source, 85 hourly_forecast: hourly_resp.source, 86 daily_forecast: daily_resp.source 87 } 88 ) 89 rescue Infrastructure::Adapters::Geocode::NotFoundError => e 90 raise AddressNotFoundError, e.message 91 rescue Infrastructure::Adapters::Weather::NotFoundError => e 92 raise WeatherNotFoundError, e.message 93 rescue Infrastructure::Adapters::Geocode::Error, 94 Infrastructure::Adapters::Weather::Error => e 95 raise ServiceError, e.message 96 end
@param address [String] address or place name to geocode @return [Result] @raise [AddressNotFoundError, WeatherNotFoundError, ServiceError]