Skip to content

Commit 4446635

Browse files
committed
Implemented key validation and explained some API exceptions.
1 parent 6c88150 commit 4446635

3 files changed

Lines changed: 34 additions & 12 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Clone/[Download](/smiley/steamapi/archive/master.zip) (and extract) the reposito
1616
Then, you can use it like this:
1717
```python
1818
>>> import steamapi
19-
>>> steamapi.core.APIConnection(api_key="ABCDEFGHIJKLMNOPQRSTUVWXYZ") # <-- Insert API key here
19+
>>> steamapi.core.APIConnection(api_key="ABCDEFGHIJKLMNOPQRSTUVWXYZ", validate_key=True) # <-- Insert API key here
2020
>>> steamapi.user.SteamUser(userurl="smileybarry") # For http://steamcommunity.com/id/smileybarry
2121
Or:
2222
>>> steamapi.user.SteamUser(76561197996416028) # Using the 64-bit Steam user ID

steamapi/core.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from .consts import API_CALL_DOCSTRING_TEMPLATE, API_CALL_PARAMETER_TEMPLATE, IPYTHON_PEEVES, IPYTHON_MODE
88
from .decorators import Singleton, cached_property, INFINITE
9-
from .errors import APIException
9+
from .errors import APIException, APIUnauthorized, APIKeyRequired, APIPrivate, APIConfigurationError
1010
from . import errors
1111

1212
GET = "GET"
@@ -226,7 +226,8 @@ def __call__(self, method=GET, **kwargs):
226226

227227
class APIInterface(object):
228228
def __init__(self, api_key=None, autopopulate=False, strict=False,
229-
api_domain="api.steampowered.com", api_protocol="http", settings=None):
229+
api_domain="api.steampowered.com", api_protocol="http", settings=None,
230+
validate_key=False):
230231
"""
231232
Initialize a new APIInterface object. This object defines an API-interacting session, and is used to call
232233
any API functions from standard code.
@@ -285,6 +286,15 @@ def set_attribute(name, value):
285286
self._autopopulate_interfaces()
286287
finally:
287288
self.__dict__['_strict'] = original_strict_value
289+
elif validate_key is True:
290+
if api_key is None:
291+
raise ValueError('"validate_key" is True, but no key was given.')
292+
293+
# Call "GetSupportedAPIList", which is guaranteed to succeed with any valid key. (Or no key)
294+
try:
295+
self.ISteamWebAPIUtil.GetSupportedAPIList.v1(key=self._api_key)
296+
except (APIUnauthorized, APIKeyRequired, APIPrivate):
297+
raise APIConfigurationError("This API key is invalid.")
288298

289299
def _autopopulate_interfaces(self):
290300
# Call the API which returns a list of API Services and Interfaces.
@@ -364,7 +374,7 @@ class APIConnection(object):
364374
# Use double curly-braces to tell Python that these variables shouldn't be expanded yet.
365375
QUERY_TEMPLATE = "{domain}/{{interface}}/{{command}}/{{version}}/".format(domain=QUERY_DOMAIN)
366376

367-
def __init__(self, api_key=None, settings={}):
377+
def __init__(self, api_key=None, settings={}, validate_key=False):
368378
"""
369379
NOTE: APIConnection will soon be made deprecated by APIInterface.
370380
@@ -378,6 +388,7 @@ def __init__(self, api_key=None, settings={}):
378388
a group of users, such as "friends", should precache player summaries,
379389
like nicknames. Recommended if you plan to use nicknames right away, since
380390
caching is done in groups and retrieving one-by-one takes a while.
391+
:param validate_key: Perform a test call to the API with the given key to test its validity.
381392
382393
"""
383394
self.reset(api_key)
@@ -386,6 +397,16 @@ def __init__(self, api_key=None, settings={}):
386397

387398
if 'precache' in settings and issubclass(type(settings['precache']), bool):
388399
self.precache = settings['precache']
400+
401+
if validate_key:
402+
if api_key is None:
403+
raise ValueError('"validate_key" is True, but no key was given.')
404+
405+
# Call "GetSupportedAPIList", which is guaranteed to succeed with any valid key. (Or no key)
406+
try:
407+
self.call("ISteamWebAPIUtil", "GetSupportedAPIList", "v1")
408+
except (APIUnauthorized, APIKeyRequired, APIPrivate):
409+
raise APIConfigurationError("This API key is invalid.")
389410

390411
def reset(self, api_key):
391412
self._api_key = api_key

steamapi/errors.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ class APIPrivate(APIFailure):
8787

8888
class APIConfigurationError(APIFailure):
8989
"""
90-
There's either no APIConnection defined, or
90+
There's either no APIConnection defined, or the parameters given to "APIConnection" or "APIInterface" are
91+
invalid.
9192
"""
9293
pass
9394

@@ -98,19 +99,19 @@ def check(response):
9899
"""
99100
if response.status_code // 100 == 4:
100101
if response.status_code == 404:
101-
raise APINotFound()
102+
raise APINotFound("The function or service you tried to call does not exist.")
102103
elif response.status_code == 401:
103-
raise APIUnauthorized()
104+
raise APIUnauthorized("This API is inaccessible to you.")
104105
elif response.status_code == 403:
105106
if '?key=' in response.request.url or '&key=' in response.request.url:
106-
raise APIPrivate()
107+
raise APIPrivate("You have no permission to use this API, or your key may be invalid.")
107108
else:
108-
raise APIKeyRequired()
109+
raise APIKeyRequired("This API requires a key to call.")
109110
elif response.status_code == 400:
110-
raise APIBadCall()
111+
raise APIBadCall("The parameters you sent didn't match this API's requirements.")
111112
else:
112-
raise APIFailure()
113+
raise APIFailure("Something is wrong with your configuration, parameters or environment.")
113114
elif response.status_code // 100 == 5:
114-
raise APIError()
115+
raise APIError("The API server has encountered an unknown error.")
115116
else:
116117
return

0 commit comments

Comments
 (0)