fkrzski/laravel-steam-api-sdk
Laravel SDK for the Steam Web API, giving you a clean, configurable PHP interface to fetch player profiles, owned games, achievements, stats, and news with expressive fluent methods and sensible defaults.
Architecture fit. 0.9.0 continues the package's role as a thin Laravel adapter over fkrzski/php-steam-api-sdk (Saloon-based Steam Web API client). The headline architectural change is the move from a flat facade surface (19 endpoint helpers removed) to resource-scoped access — Steam::users()->groups($id), Steam::stats()->currentPlayers(440). This mirrors Steam's own interface grouping (IPlayerService, ISteamUserStats, ISteamWebAPIUtil) and makes the client self-documenting at the call site. For a team already running Laravel queues and jobs, the RespectsSteamRateLimit job middleware plus the new configurable limits slot into existing idioms rather than inventing new ones.
Integration feasibility. Low-friction install: composer package, config publish, env vars. Two extension points land in this release and both are the right shape: (a) steam-api.http.sender / STEAM_API_SENDER names a Saloon Sender that the container builds, so middleware (logging, retries, tracing headers, request signing) lives in a bound subclass instead of a fork; (b) Nightwatch reporting is zero-config when laravel/nightwatch is present. The new ISteamWebAPIUtil coverage is genuinely useful operationally — serverTime() returns Steam's clock without transmitting the key (a free health/clock-skew probe), and supportedApis() lets us assert at deploy time which methods a key can actually call.
Technical risk. This is a pre-1.0 package shipping four breaking changes in a single minor, and the release notes explicitly flag a counter reset precedent from 0.4.0. Ranked:
http.sender, rate_limit.limits, or rate_limit.cooldown — defaults apply, but STEAM_API_SENDER and STEAM_API_RATE_LIMIT_COOLDOWN are read and ignored with no error. Anyone setting those env vars will believe they are configured when they are not.Steam::connector()->sender() now returns the base SDK's SteamSender, not GuzzleSender. addMiddleware(), getHandlerStack(), getGuzzleClient() are gone. Any existing middleware wiring fails — typically as a fatal at first request, not at boot.InvalidSteamRateLimitStoreException → InvalidSteamRateLimitOptionException. Catch blocks referencing the old name silently stop catching, converting a handled condition into a 500.100000_every_utc_midnight; a persistent rate-limit store restarts from zero once, permitting a short burst above the intended budget in the window after deploy.about --json key rename. daily_requests_remaining → requests_remaining (now a list). Any dashboard, deploy gate, or alerting parser breaks or silently reads null.Two claims worth independent verification before sign-off: that Nightwatch strips the API key from recorded URLs (security-relevant, and redaction regressions are quiet), and that serverTime() never sends the key (should be asserted with a mocked sender in a test).
Key questions.
sender() / Guzzle middleware, or can we adopt the container-bound GuzzleSender with no prior state?php artisan about --json?Stack fit. Assumes Laravel with Saloon already resolvable (it is a transitive dependency of the base SDK), a queue driver for the rate-limit middleware's job-release behavior, and a cache/persistent store for local metering. Optional: laravel/nightwatch for observability. [] for rate_limit.limits cleanly disables local metering — useful in test and CI environments where we do not want cross-test quota interference.
Migration path. The four breaking changes are mechanical but uneven in difficulty:
GuzzleSender subclass, bind it in a service provider, name it in STEAM_API_SENDER.about --json consumers.Compatibility. Hard lockstep with fkrzski/php-steam-api-sdk ^0.9 — the two must move together. Confirm the resolved Saloon major matches what our middleware subclass targets. Verify the rate-limit store driver supports the new limit key format before deploying, since the old counter key becomes dead state.
Sequencing.
http.sender, rate_limit.limits, and rate_limit.cooldown are present in the published file.about --json parser update, landed together with the dashboard change.Maintenance. Pin to ^0.9 and assume another breaking minor before 1.0. Budget a recurring upgrade slot rather than treating this as a one-off. The recurring tax is config drift: every release must be preceded by a diff of the package's shipped config against ours, because Laravel's shallow merge makes omissions invisible.
Support. Maintainer-led package with a single primary author — a real bus-factor consideration for anything on the critical path. Mitigations: the docs are decent and improving (a dedicated rate-limiting page ships here), the base SDK is a separate dependency we could call directly as an escape hatch, and the surface we use is small enough that vendoring is viable. Pre-1.0 churn means upstream support questions often resolve to "upgrade."
Scaling. Replacing the hardcoded 100,000/day with configurable allow/every/sleep windows is the most operationally valuable change in the release: it lets us tune per environment and per key tier. Two caveats. First, the local meter is advisory — Steam's per-key server-side quotas still apply, so the local limit must be set below the real ceiling, not at it. Second, the corrected reset at 00:00 UTC combined with RespectsSteamRateLimit releasing jobs until then creates a predictable thundering herd at midnight UTC when a budget is exhausted; add jitter to released jobs or stagger the workload.
Failure modes to instrument.
about check in the deploy script.cooldown applies only to responses lacking Retry-After. Verify it is appropriate for our burst profile.STEAM_API_SENDER — fails at connector construction, so it surfaces on first Steam call rather than at boot; smoke-test one call post-deploy.InvalidSteamRateLimitOptionException if the rename is missed in a catch block.UnexpectedValueException and failed the whole call; worth confirming our batch sizes and that the new friendsOnly() fake covers the case in tests.Ramp-up. The resource-based API trades a flat, guessable facade for discoverability that depends on the API reference — slightly steeper for a new engineer's first call, meaningfully better for anyone reading code later. The testing story is the onboarding win: factory coverage for ISteamWebAPIUtil responses and PlayerSummaryFactory::friendsOnly() on the fluent fake under ->webApi() means a new contributor can write a realistic test without hitting Steam or hand-rolling fixtures. Estimate: half a day for an engineer familiar with the codebase to complete the migration on a moderate integration; one to two days if custom Guzzle middleware or a persistent rate-limit store is in play.
How can I help you explore Laravel packages today?