Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial client and requests implementation

  • Loading branch information...
commit a63502e287c04f934d1d27da98d2046bdf0a31aa 1 parent 12dd6f5
@hmarr hmarr authored
View
1  .gitignore
@@ -0,0 +1 @@
+*.pyc
View
4 gocardless/__init__.py
@@ -0,0 +1,4 @@
+from .client import Client
+
+environment = 'production'
+
View
66 gocardless/client.py
@@ -0,0 +1,66 @@
+import json
+
+import gocardless
+from .request import Request
+from .exceptions import ClientError
+
+
+class Client(object):
+
+ API_PATH = '/api/v1'
+
+ BASE_URLS = {
+ 'production': 'https://gocardless.com',
+ 'sandbox': 'https://sandbox.gocardless.com',
+ }
+
+ base_url = None
+
+ @classmethod
+ def get_base_url(cls):
+ """Return the correct base URL for the current environment. If one has
+ been manually set, default to that.
+ """
+ return cls.base_url or cls.BASE_URLS[gocardless.environment]
+
+ def __init__(self, **account_details):
+ if 'app_id' not in account_details:
+ raise ValueError('You must provide an app_id')
+
+ if 'app_secret' not in account_details:
+ raise ValueError('You must provide an app_secret')
+
+ self._app_id = account_details['app_id']
+ self._app_secret = account_details['app_secret']
+ self._access_token = account_details.get('token')
+ self._merchant_id = account_details.get('merchant_id')
+
+ def api_get(self, path, **kwargs):
+ """Issue an GET request to the API server.
+
+ :param path: the path that will be added to the API prefix
+ :param params: query string parameters
+ """
+ return self._request('get', Client.API_PATH + path, **kwargs)
+
+ def _request(self, method, path, **kwargs):
+ """Send a request to the GoCardless API servers.
+
+ :param method: the HTTP method to use (e.g. +:get+, +:post+)
+ :param path: the path fragment of the URL
+ """
+ request_url = Client.get_base_url() + path
+ request = Request(method, request_url)
+
+ if 'auth' in kwargs:
+ # If using HTTP basic auth, let requests handle it
+ request.use_http_auth(kwargs['auth'])
+ else:
+ # Default to using bearer auth with the access token
+ request.use_bearer_auth(self._access_token)
+
+ request.set_payload(kwargs.get('data'))
+
+ return request.perform()
+
+
View
4 gocardless/exceptions.py
@@ -0,0 +1,4 @@
+
+class ClientError(Exception):
+ pass
+
View
36 gocardless/request.py
@@ -0,0 +1,36 @@
+import json
+import requests
+
+
+class Request(object):
+
+ def __init__(self, method, url):
+ self._method = method
+ self._url = url
+ self._opts = {'headers': {'Accept': 'application/json'}}
+
+ if not self._valid_method(method):
+ raise ValueError('Invalid method {}'.format(method))
+
+ def _valid_method(self, method):
+ return method in ('get', 'post', 'put')
+
+ def use_http_auth(self, username, password):
+ self._opts['auth'] = (username, password)
+
+ def use_bearer_auth(self, token):
+ auth_header = 'bearer {}'.format(token)
+ self._opts['headers']['Authorization'] = auth_header
+
+ def set_payload(self, payload):
+ if payload is not None:
+ # Set the payload type - always JSON
+ self._opts['headers']['Content-Type'] = 'application/json'
+ # And JSON encode the data
+ self._opts['data'] = json.dumps(payload)
+
+ def perform(self):
+ fetch_func = getattr(requests, self._method)
+ response = fetch_func(self._url, **self._opts)
+ return json.loads(response.content)
+
View
0  test/__init__.py
No changes.
View
40 test/client_test.py
@@ -0,0 +1,40 @@
+import unittest
+
+import gocardless
+from gocardless.client import Client
+
+
+class ClientTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.account_details = {
+ 'app_id': 'id01',
+ 'app_secret': 'sec01',
+ 'token': 'tok01',
+ 'merchant_id': 'MERCH01',
+ }
+ self.client = Client(**self.account_details)
+
+ def test_base_url_returns_the_correct_url_for_production(self):
+ gocardless.environment = 'production'
+ self.assertEqual(Client.get_base_url(), 'https://gocardless.com')
+
+ def test_base_url_returns_the_correct_url_for_sandbox(self):
+ gocardless.environment = 'sandbox'
+ self.assertEqual(Client.get_base_url(), 'https://sandbox.gocardless.com')
+
+ def test_base_url_returns_the_correct_url_when_set_manually(self):
+ Client.base_url = 'https://abc.gocardless.com'
+ self.assertEqual(Client.get_base_url(), 'https://abc.gocardless.com')
+
+ def test_app_id_required(self):
+ self.account_details.pop('app_id')
+ with self.assertRaises(ValueError):
+ Client(**self.account_details)
+
+ def test_app_secret_required(self):
+ self.account_details.pop('app_secret')
+ with self.assertRaises(ValueError):
+ Client(**self.account_details)
+
+
View
62 test/request_test.py
@@ -0,0 +1,62 @@
+import unittest
+import mock
+
+#from gocardless import request
+import gocardless.request
+
+
+class RequestTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.request = gocardless.request.Request('get', 'http://test.com')
+
+ def test_valid_method_allows_valid_methods(self):
+ for method in ('get', 'post', 'put'):
+ self.assertTrue(self.request._valid_method('get'))
+
+ def test_valid_method_disallows_invalid_methods(self):
+ self.assertFalse(self.request._valid_method('fake_method'))
+
+ def test_use_bearer_auth_sets_auth_header(self):
+ self.request.use_bearer_auth('token')
+ self.assertEqual(self.request._opts['headers']['Authorization'],
+ 'bearer token')
+
+ def test_use_http_auth_sets_auth_details_in_opts(self):
+ self.request.use_http_auth('user', 'pass')
+ self.assertEqual(self.request._opts['auth'], ('user', 'pass'))
+
+ def test_set_payload_ignores_null_payloads(self):
+ self.request.set_payload(None)
+ self.assertTrue('Content-Type' not in self.request._opts['headers'])
+ self.assertTrue('data' not in self.request._opts)
+
+ def test_set_payload_sets_content_type(self):
+ self.request.set_payload({'a': 'b'})
+ self.assertEqual(self.request._opts['headers']['Content-Type'],
+ 'application/json')
+
+ def test_set_payload_encodes_payload(self):
+ self.request.set_payload({'a': 'b'})
+ self.assertEqual(self.request._opts['data'], '{"a": "b"}')
+
+ @mock.patch('gocardless.request.requests')
+ def test_perform_calls_get_for_gets(self, mock_requests):
+ mock_requests.get.return_value.content = '{"a": "b"}'
+ self.request.perform()
+ mock_requests.get.assert_called_once_with(mock.ANY, headers=mock.ANY)
+
+ @mock.patch('gocardless.request.requests')
+ def test_perform_calls_post_for_posts(self, mock_requests):
+ mock_requests.post.return_value.content = '{"a": "b"}'
+ self.request._method = 'post'
+ self.request.perform()
+ mock_requests.post.assert_called_once_with(mock.ANY, headers=mock.ANY)
+
+ @mock.patch('gocardless.request.requests.get')
+ def test_perform_decodes_json(self, mock_get):
+ response = mock.Mock()
+ response.content = '{"a": "b"}'
+ mock_get.return_value = response
+ self.assertEqual(self.request.perform(), {'a': 'b'})
+
Please sign in to comment.
Something went wrong with that request. Please try again.