Skip to content

Commit

Permalink
Merge pull request #8 from alphagov/add-data-client
Browse files Browse the repository at this point in the history
Add DataAPIClient and tests
  • Loading branch information
quis committed May 1, 2015
2 parents 51052b9 + 1389900 commit 6a47299
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 18 deletions.
2 changes: 1 addition & 1 deletion dmutils/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.3.0'
__version__ = '0.4.0'
82 changes: 69 additions & 13 deletions dmutils/apiclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@
logger = logging.getLogger(__name__)


class APIError(requests.HTTPError):
def __init__(self, http_error):
super(APIError, self).__init__(
http_error,
response=http_error.response,
request=http_error.request)

@property
def response_message(self):
try:
return self.response.json()['error']
except TypeError:
return str(self.response.content)


class BaseAPIClient(object):
def __init__(self, base_url=None, auth_token=None, enabled=None):
self.base_url = base_url
Expand All @@ -15,22 +30,31 @@ def __init__(self, base_url=None, auth_token=None, enabled=None):
def _put(self, url, data):
return self._request("PUT", url, data=data)

def _get(self, url, params):
def _get(self, url, params=None):
return self._request("GET", url, params=params)

def _post(self, url, data):
return self._request("POST", url, data=data)

def _request(self, method, url, data=None, params=None):
if self.enabled:
logger.debug("API request %s %s", method, url)
headers = {
"Content-type": "application/json",
"Authorization": "Bearer {}".format(self.auth_token),
}
response = requests.request(
method, url,
headers=headers, data=data, params=params)
response.raise_for_status()

return response.json()
try:
logger.debug("API request %s %s", method, url)
headers = {
"Content-type": "application/json",
"Authorization": "Bearer {}".format(self.auth_token),
}
response = requests.request(
method, url,
headers=headers, data=data, params=params)
response.raise_for_status()

return response.json()
except requests.HTTPError as e:
raise APIError(e)
except requests.RequestException as e:
logger.exception(e.message)
raise


class SearchAPIClient(BaseAPIClient):
Expand All @@ -56,7 +80,7 @@ def index(self, service_id, service, supplier_name):
url = self._url("/{}".format(service_id))
data = self._convert_service(service_id, service, supplier_name)

return self._put(url, data)
return self._put(url, data=data)

def _convert_service(self, service_id, service, supplier_name):
data = {k: service[k] for k in self.FIELDS if k in service}
Expand All @@ -66,3 +90,35 @@ def _convert_service(self, service_id, service, supplier_name):
return {
"service": data
}


class DataAPIClient(BaseAPIClient):
def init_app(self, app):
self.base_url = app.config['DM_DATA_API_URL']
self.auth_token = app.config['DM_DATA_API_AUTH_TOKEN']

def get_service(self, service_id):
return self._get(
"{}/services/{}".format(self.base_url, service_id))['services']

def find_service(self, supplier_id=None, page=None):
params = {}
if supplier_id is not None:
params['supplier_id'] = supplier_id
if page is not None:
params['page'] = page

return self._get(
self.base_url + "/services",
params=params)['services']

def update_service(self, service_id, service, user, reason):
return self._post(
"{}/services/{}".format(self.base_url, service_id),
data={
"update_details": {
"updated_by": user,
"update_reason": reason,
},
"services": service,
})
82 changes: 78 additions & 4 deletions tests/test_apiclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
import json

import requests_mock
import requests
import pytest
import mock

from dmutils.apiclient import SearchAPIClient
from dmutils.apiclient import SearchAPIClient, DataAPIClient, APIError


@pytest.yield_fixture
Expand All @@ -20,6 +19,11 @@ def search_client():
return SearchAPIClient('http://baseurl', 'auth-token', True)


@pytest.fixture
def data_client():
return DataAPIClient('http://baseurl', 'auth-token', True)


@pytest.fixture
def service():
"""A stripped down G6-IaaS service"""
Expand Down Expand Up @@ -127,9 +131,9 @@ def test_should_not_call_search_api_is_es_disabled(
assert result is None
assert not rmock.called

def test_should_raise_requests_error_on_failure(
def test_should_raise_error_on_failure(
self, search_client, rmock, service):
with pytest.raises(requests.HTTPError):
with pytest.raises(APIError):
rmock.put(
'http://baseurl/g-cloud/services/12345',
json={'error': 'some error'},
Expand All @@ -141,3 +145,73 @@ def load_example_listing(name):
file_path = os.path.join("example_listings", "{}.json".format(name))
with open(file_path) as f:
return json.load(f)


class TestDataApiClient(object):
def test_init_app_sets_attributes(self, data_client):
app = mock.Mock()
app.config = {
"DM_DATA_API_URL": "http://example",
"DM_DATA_API_AUTH_TOKEN": "example-token",
}
data_client.init_app(app)

assert data_client.base_url == "http://example"
assert data_client.auth_token == "example-token"

def test_get_service(self, data_client, rmock):
rmock.get(
"http://baseurl/services/123",
json={"services": "result"},
status_code=200)

result = data_client.get_service(123)

assert result == "result"
assert rmock.called

def test_find_service(self, data_client, rmock):
rmock.get(
"http://baseurl/services",
json={"services": "result"},
status_code=200)

result = data_client.find_service()

assert result == "result"
assert rmock.called

def test_find_service_adds_page_parameter(self, data_client, rmock):
rmock.get(
"http://baseurl/services?page=2",
json={"services": "result"},
status_code=200)

result = data_client.find_service(page=2)

assert result == "result"
assert rmock.called

def test_find_service_adds_supplier_id_parameter(self, data_client, rmock):
rmock.get(
"http://baseurl/services?supplier_id=1",
json={"services": "result"},
status_code=200)

result = data_client.find_service(supplier_id=1)

assert result == "result"
assert rmock.called

def test_update_service(self, data_client, rmock):
rmock.post(
"http://baseurl/services/123",
json={"services": "result"},
status_code=200,
)

result = data_client.update_service(
123, {"foo": "bar"}, "person", "reason")

assert result == {"services": "result"}
assert rmock.called

0 comments on commit 6a47299

Please sign in to comment.