A method the SDK does not cover is one Saloon Request away. Sent through SteamConnector, it
gets what the shipped requests get: the API key, the rate limit,
retries, hooks, debug() with the key masked, and
SDK exceptions.
use Fkrzski\SteamApiSdk\Contracts\SendsNoApiKey;use Saloon\Enums\Method;use Saloon\Http\Request;use Saloon\Http\Response;
final class GetCmListRequest extends Request implements SendsNoApiKey{ protected Method $method = Method::GET;
public function __construct( public readonly int $cellId, ) {}
public function resolveEndpoint(): string { return '/ISteamDirectory/GetCMList/v1/'; }
protected function defaultQuery(): array { return ['cellid' => $this->cellId]; }
/** * @return list<string> */ public function createDtoFromResponse(Response $response): array { return $response->json('response.serverlist'); }}$servers = $connector->send(new GetCmListRequest(0))->dto();sendAsync(), pool() and a SteamFake or MockClient take it as they take the SDK’s own requests.
The API key
Section titled “The API key”The connector puts the configured key on every request, and refuses one locally with
ApiKeyNotConfiguredException when the config carries none. Two marker interfaces change that:
| Request | Key configured | No key configured |
|---|---|---|
plain Request |
sent | ApiKeyNotConfiguredException, nothing goes out |
implements SendsOptionalApiKey |
sent | sent without one |
implements SendsNoApiKey |
stripped from the query | sent |
Mark a method Steam serves anonymously SendsNoApiKey, so the key stays off a URL that does not
need it, and the request off the key’s budget and cool-down
(limited apart).
SendsOptionalApiKey is for one that answers both ways but differently, as
GetSupportedAPIList does.
Language
Section titled “Language”HasLanguage lets the default language reach
a method that reads Steam’s l parameter. It asks for a public ?Language $language, and the
connector fills l only while that is null, so the request sends its own:
use Fkrzski\SteamApiSdk\Contracts\HasLanguage;use Fkrzski\SteamApiSdk\Enums\Language;
final class LocalisedRequest extends Request implements HasLanguage{ public function __construct( public readonly int $appId, public readonly ?Language $language = null, ) {}
protected function defaultQuery(): array { return array_filter(['appid' => $this->appId, 'l' => $this->language?->value]); }
// ...}Failures
Section titled “Failures”A request with no mapping of its own fails as the status table
says for any endpoint: a key error raises InvalidApiKeyException, any other 401 or 403
raises ProfileNotPublicException, and every other 4xx or 5xx raises SteamApiException. A
5xx and a request Steam never answered are retried.
The request’s own getRequestException() runs before the connector’s, and null hands the
response back to it, so map only the statuses you know. Extending SteamApiException keeps one
catch covering everything, and handing it the response sets the code and the method prefix:
use Fkrzski\SteamApiSdk\Exceptions\SteamApiException;
final class CmListUnavailableException extends SteamApiException {}public function getRequestException(Response $response, ?Throwable $senderException): ?Throwable{ return $response->status() === 403 ? new CmListUnavailableException('Steam refused the cell.', $response) : null;}hasRequestFailed() flags a failure Steam reports in a 200 payload. It raises
SteamApiException with code 200, or what getRequestException() returns, and is never retried:
public function hasRequestFailed(Response $response): bool{ return $response->json('response.result') !== 1;}