Skip to content

Commit

Permalink
Use headers only (#446)
Browse files Browse the repository at this point in the history
* Use headers only

* Check if api_key is required in params for some endpoints

* Add unit test for api_keys in params

* Fix blank lines

* Remove more spaces

* Add a set of excluded paths

* flake

* flake8

* Flake8 on another file
  • Loading branch information
ssc3 authored Oct 4, 2019
1 parent 1875064 commit b4cb2df
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 13 deletions.
44 changes: 36 additions & 8 deletions datadog/api/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
)
from datadog.api.http_client import resolve_http_client
from datadog.util.compat import is_p3k
from datadog.util.format import construct_url
from datadog.util.format import construct_url, construct_path


log = logging.getLogger('datadog.api')
Expand Down Expand Up @@ -90,9 +90,22 @@ def submit(cls, method, path, api_version=None, body=None, attach_host_name=Fals
if _api_key is None:
raise ApiNotInitialized("API key is not set."
" Please run 'initialize' method first.")
params['api_key'] = _api_key

# Set api and app keys in headers
headers = {}
headers['DD-API-KEY'] = _api_key
if _application_key:
params['application_key'] = _application_key
headers['DD-APPLICATION-KEY'] = _application_key

# Check if the api_version is provided
if not api_version:
api_version = _api_version

# set api and app keys in params only for some endpoints
if cls._set_api_and_app_keys_in_params(api_version, path):
params['api_key'] = _api_key
if _application_key:
params['application_key'] = _application_key

# Attach host name to body
if attach_host_name and body:
Expand All @@ -110,12 +123,7 @@ def submit(cls, method, path, api_version=None, body=None, attach_host_name=Fals
if 'tags' in params and isinstance(params['tags'], list):
params['tags'] = ','.join(params['tags'])

# Check if the api_version is provided
if not api_version:
api_version = _api_version

# Process the body, if necessary
headers = {}
if isinstance(body, dict):
body = json.dumps(body)
headers['Content-Type'] = 'application/json'
Expand Down Expand Up @@ -233,3 +241,23 @@ def _backoff_status(cls):
backed_off_time = now - cls._backoff_timestamp
backoff_time_left = cls._backoff_period - backed_off_time
return round(backed_off_time, 2), round(backoff_time_left, 2)

@classmethod
def _set_api_and_app_keys_in_params(cls, api_version, path):
"""
Some endpoints need api and app keys to be set in params only
For these endpoints, api and app keys in headers are ignored
:return: True if this endpoint needs api and app keys params set
"""
constructed_path = construct_path(api_version, path)

set_of_paths = {
"v1/series",
"v1/check_run",
"v1/events",
"v1/screen",
}
if constructed_path in set_of_paths:
return True

return False
4 changes: 4 additions & 0 deletions datadog/util/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ def pretty_json(obj):

def construct_url(host, api_version, path):
return "{}/api/{}/{}".format(host.strip("/"), api_version.strip("/"), path.strip("/"))


def construct_path(api_version, path):
return "{}/{}".format(api_version.strip("/"), path.strip("/"))
2 changes: 2 additions & 0 deletions tests/unit/api/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def raise_for_status(self):
class MyCreatable(CreateableAPIResource):
_resource_name = 'creatables'

class MyParamsApiKeyCreatable(CreateableAPIResource):
_resource_name = 'series'

class MyUpdatable(UpdatableAPIResource):
_resource_name = 'updatables'
Expand Down
34 changes: 29 additions & 5 deletions tests/unit/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
DatadogAPIWithInitialization,
DatadogAPINoInitialization,
MyCreatable,
MyParamsApiKeyCreatable,
MyUpdatable,
MyDeletable,
MyGetable,
Expand Down Expand Up @@ -93,13 +94,36 @@ def test_request_parameters(self):
# Assert `requests` parameters
self.assertIn('params', options)

self.assertIn('api_key', options['params'])
self.assertEqual(options['params']['api_key'], API_KEY)
self.assertIn('application_key', options['params'])
self.assertEqual(options['params']['application_key'], APP_KEY)
self.assertIn('headers', options)
self.assertEqual(options['headers']['Content-Type'], 'application/json')
self.assertEqual(options['headers']['DD-API-KEY'], API_KEY)
self.assertEqual(options['headers']['DD-APPLICATION-KEY'], APP_KEY)


def test_request_parameters_api_keys_in_params(self):
"""
API parameters are set with `initialize` method.
"""
# Test API, application keys, API host, and some HTTP client options
initialize(api_key=API_KEY, app_key=APP_KEY, api_host=API_HOST)

# Make a simple API call
MyParamsApiKeyCreatable.create()

_, options = self.request_mock.call_args()

# Assert `requests` parameters
self.assertIn('params', options)

self.assertIn('headers', options)
self.assertEqual(options['headers'], {'Content-Type': 'application/json'})

# for resources in MyParamsApiKey, api key and application key needs to be in url params
# any api and app keys in headers are ignored
self.assertEqual(options['headers']['Content-Type'], 'application/json')
self.assertEqual(options['params']['api_key'], API_KEY)
self.assertEqual(options['params']['application_key'], APP_KEY)



def test_initialize_options(self):
"""
Expand Down

0 comments on commit b4cb2df

Please sign in to comment.