dnsimmons/openweather
dnsimmons/openweather is a Laravel wrapper for the OpenWeather API, offering a simple, expressive interface to fetch current conditions, forecasts, and other weather data in your PHP applications with minimal configuration.
Before installing, note that this package is archived (last release Dec 2021) and has minimal adoption. It is a thin wrapper over the OpenWeatherMap HTTP API, so the cost of replacing it later is low — but verify its composer.json constraints against your Laravel/PHP version before you commit.
composer require dnsimmons/openweather
php artisan vendor:publish --provider="Dnsimmons\OpenWeather\OpenWeatherServiceProvider"
config/openweather.php and vendor/dnsimmons/openweather/src/ first. That is where the API key, base URL, units, and the facade/class bindings actually live — the README is sparse and the source is the real documentation..env as OPENWEATHER_API_KEY (or whatever key name the config file expects) and confirm the service provider is auto-discovered. Run php artisan config:clear after editing.use Illuminate\Support\Facades\Cache;
use Dnsimmons\OpenWeather\Facades\OpenWeather;
$weather = Cache::remember('owm:current:london', now()->addMinutes(10), function () {
return OpenWeather::getCurrentWeather('London', 'metric');
});
If the facade alias differs, check the package's service provider register()/boot() methods — the class names are the only reliable guide.
Wrap it in your own service. Never call the facade from Blade, controllers, or commands directly. Create App\Services\WeatherService that returns your own DTO or array shape (temperature, condition, icon, observedAt). Since the underlying package is unmaintained, this boundary is what lets you swap in a raw Http::get('api.openweathermap.org/...') call, or a different provider, without touching views.
Cache aggressively, key by intent. OpenWeatherMap's free tier is rate-limited (roughly 60 req/min, 1M/month). Cache keys should encode everything that changes the response: owm:{endpoint}:{round(lat,2)},{round(lon,2)}:{units}:{lang}. TTL guidance: current conditions 5–15 min, multi-day forecast 30–60 min, geocoding result forever (city coordinates don't move). Round coordinates in the key — otherwise every map pan creates a cache miss.
Geocode once, store coordinates. City-name lookups are brittle (name collisions, accents, and OWM's own matching quirks). If you have a locations table, store lat/lon at creation time and use coordinates for all subsequent calls. This also cuts an API call per request.
Serve from a scheduled command for dashboards. For a weather widget on a high-traffic page, don't fetch inline. Run weather:refresh every 10 minutes via the scheduler, write to cache or a table, and let requests read that. This makes rate limiting a non-issue and degrades gracefully when OWM is down.
Normalize units and language explicitly. Pass units (metric/imperial/standard) and lang per call rather than relying on the config default, especially if you support multiple locales. Convert standard (Kelvin) at your boundary, not in the view.
Test with Http::fake. Because this package ultimately uses Laravel's/Guzzle's HTTP client, faking works:
Http::fake(['api.openweathermap.org/*' => Http::response($fixture, 200)]);
Keep a few real response fixtures in tests/fixtures/ — the payload is large and nesting is deep, so hand-written arrays drift from reality.
Handle failures as "no weather," not as an exception page. Wrap calls in try/catch, log at warning, return null, and have the view render a placeholder. Weather is decorative infrastructure; it must never 500 a page.
Http::get() against the documented API instead; that's essentially all this package is.401 Unauthorized on a freshly generated key usually means "wait," not "wrong config." Check this before debugging the package.oneCall-style call in the package can return 401 even with a valid key on a free account — you must add a card and subscribe to the free tier in the OWM dashboard. Older 2.5 endpoints (current/forecast) still work on the plain free tier.timezone is an offset in seconds, not a timezone name. Use Carbon::createFromTimestampUTC($ts)->setTimezone(...). Do not createFromTimestamp and assume local — your users in another region will see the wrong hour.main, weather[0], and rain/snow are not always present (e.g. rain appears only when it's raining). Use data_get($response, 'weather.0.icon') with a fallback.appid as a query parameter, so the key ends up in URL logs, exception traces, and Telescope entries. Sanitize before logging.429 and back off. If you hit the rate limit, add ->retry() or a small backoff; hammering makes it worse. Combine with the caching pattern above.01d, 10n, etc. You must map these to your own SVG set (01d → clear-day.svg) and handle day/night variants. The package will not do this for you.vcs repository entry in composer.json, and point at your fork. Contributing upstream is not an option on an archived repo.How can I help you explore Laravel packages today?