Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Weather Underground Laravel Package

suncat/weather-underground

A Laravel/PHP wrapper for the Weather Underground API that lets you fetch current conditions and forecasts for a given location. Configure your API key and query weather data through a clean, simple interface in your applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony2 bundle, not a Laravel package, so "getting started" means either spinning it up inside a Symfony 2.x kernel to study it, or reading the source to port the client. Given the repo has zero stars/dependents and the upstream API is defunct, treat it as a reference implementation, not a dependency.

Minimal path to inspect it:

composer require suncat/weather-underground

Register the bundle in app/AppKernel.php:

$bundles = [
    // ...
    new Suncat\WeatherUndergroundBundle\WeatherUndergroundBundle(),
];

Configure the key in app/config/config.yml (confirm the exact root key in DependencyInjection/Configuration.php):

suncat_weather_underground:
    api_key: "%weather_underground_api_key%"

Where to look first:

  1. DependencyInjection/Configuration.php — the real config schema (api_key, base URL, maybe timeout).
  2. Resources/config/services.yml — the service ID you actually inject; aliases are often not intuitive.
  3. The Service/ or Client/ directory — the HTTP wrapper class is the only thing worth porting.

First use case: current conditions for a city.

$client = $this->get('suncat_weather_underground.client'); // verify ID in services.yml
$conditions = $client->getConditions('CA', 'San_Francisco');

Before writing that line, verify the service ID — the bundle predates autowiring, so you're pulling from the container by string. grep -r "public: true" Resources/config/ or bin/console debug:container weather in a Symfony 2.x app is faster than guessing.

If you're staying in Laravel: do not install this. Copy the client class, drop the Symfony DI annotations, and rewire it to Illuminate\Support\Facades\Http. See the porting pattern below.

Implementation Patterns

1. Inject, don't resolve from the container. The bundle's value in a real app is that the client is a service. Move the call behind your own interface so you can swap providers later (you will — see Gotchas).

final class WeatherService
{
    public function __construct(private WeatherUndergroundClient $client) {}

    public function current(string $state, string $city): WeatherSnapshot
    {
        $raw = $this->client->getConditions($state, $city);
        return WeatherSnapshot::fromArray($raw);
    }
}

2. Wrap it in a cache decorator. Free-tier WU allowed ~500 calls/day and ~10/min. Even when the API worked, you cached. The decorator also becomes your seam for tests:

class CachedWeatherService implements WeatherProvider
{
    public function __construct(
        private WeatherProvider $inner,
        private CacheItemPoolInterface $cache,
        private int $ttl = 600,
    ) {}

    public function current(string $state, string $city): WeatherSnapshot
    {
        $key = "wu:{$state}:{$city}";
        return $this->cache->getItem($key)->get() ?? $this->refresh($key, $state, $city);
    }
}

3. Porting the client to Laravel — the pragmatic move for a Laravel dev. The bundle's client is a thin HTTP wrapper; replace its transport with the HTTP facade and keep the response normalization:

class WeatherUndergroundClient
{
    public function __construct(
        private string $apiKey,
        private string $baseUrl = 'http://api.wunderground.com/api',
    ) {}

    public function getConditions(string $state, string $city): array
    {
        $url = sprintf('%s/%s/conditions/q/%s/%s.json', $this->baseUrl, $this->apiKey, $state, $city);

        return Http::timeout(5)
            ->retry(2, 200)
            ->get($url)
            ->throw()
            ->json('current_observation', []);
    }
}

Bind it in a service provider and expose a facade; then you can fake it in tests with Http::fake() instead of mocking a Symfony container.

4. Scheduled ingestion. Forecasts are naturally a cron job, not a request-time call. In Laravel, a Schedule::command('weather:sync')->hourly(); in Symfony2, a console command wired through crontab. Pull the data, persist it, and serve pages from your own table — this decouples your app from provider outages and rate limits.

5. Response normalization at the boundary. The API returns current_observation, forecast, hourly_forecast, etc. — deeply nested and inconsistent across endpoints. Map to your own DTO in one place (WeatherSnapshot::fromArray) so a provider swap is a single-file change.

6. Test seam. Wrap the transport in a WeatherTransport interface with a FakeTransport returning fixture JSON. Do not assert on the live API — the bundle almost certainly has no tests of its own, so yours are the only safety net.

Gotchas and Tips

  • The upstream API is gone. IBM/Weather Underground discontinued the free API key program at the end of 2018. Requests to api.wunderground.com no longer return usable data. Any tutorial or example in this bundle's README is historically accurate and operationally dead. Budget for a replacement (Open-Meteo needs no key; OpenWeatherMap, WeatherAPI, or Tomorrow.io if you need forecasts/SLA) regardless of how clean the integration looks.
  • Symfony2 is EOL. End of life since November 2018, no security patches. The bundle's composer.json likely constrains symfony/symfony to ~2.x and PHP to ~5.x, which will conflict with any modern project. Installing it in a current Laravel app is not viable — port the class.
  • Zero adoption means zero documentation surface. No dependents means no Stack Overflow answers, no forks fixing bugs, no usage examples beyond the README. Read Configuration.php and services.yml yourself; they are the docs.
  • Config key mismatch is the #1 failure. If the tree root doesn't match what you wrote in config.yml, Symfony2 silently ignores the config and the client gets a null API key. Run bin/console config:dump-reference suncat_weather_underground to see the real schema. In the Laravel port, an empty WU_API_KEY env var is the same trap — fail fast in the constructor.
  • Hardcoded HTTP layer. Pre-2015 Symfony bundles often called file_get_contents/curl directly rather than injecting a Guzzle client, which makes mocking painful. If that's the case here, the extension point is to decorate the client service with your own interface wrapper rather than subclassing.
  • Error handling is likely absent or naive. Expect json_decode($response) on a raw string with no status check. In the port, use ->throw() and map 401/429/5xx to distinct exceptions; 429 (rate limit) should feed your cache TTL backoff.
  • Response shape drift. current_observation keys vary by station and by endpoint; defensive reads ($data['current_observation']['temp_c'] ?? null) beat assuming presence. City lookups via q/CA/San_Francisco.json are brittle for non-US addresses — geocode to lat/long upstream and use the lat/long query form.
  • Extension points worth knowing: override the service definition in your app's services.yml to substitute a decorated client, and keep your own interface as the injection target in application code. That way the bundle's class name only appears in one service file, and replacing it later is a wiring change, not a refactor.
  • Bottom line for a Laravel team: use this repo as a specification of a thin weather client, not as a dependency. The value you'd actually leverage is the response-mapping shape — and you can rebuild that against a live provider in an afternoon with Http::fake()-backed tests.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource