Skip to content

Commit

Permalink
Merge pull request #94 from era/master
Browse files Browse the repository at this point in the history
Refresh token support
  • Loading branch information
filipeximenes committed Dec 20, 2015
2 parents c88cd57 + 14b44d2 commit b9e4b54
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 5 deletions.
19 changes: 19 additions & 0 deletions docs/source/adapter.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
==========
Adapter
==========

Authentication helpers
---------------------

You can implement the ```refresh_authentication``` and ```is_authentication_expired``` methods in your Tapioca Client to refresh your authentication token every time that it expires.
```is_authentication_expired``` receives an error object from the request method (it contains the server response and HTTP Status code). You can use it to decide if a request failed because of the token. This method should return true if the authentication is expired or false otherwise.

If the authentication is expired, ```refresh_authentication``` is called. This method does not receive any parameter.

.. code-block:: python
def is_authentication_expired(self,error)
....
def refresh_authentication(self):
...
10 changes: 8 additions & 2 deletions tapioca/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ def get_iterator_next_request_kwargs(self, iterator_request_kwargs,
response_data, response):
raise NotImplementedError()

def is_authentication_expired(self, error):
raise NotImplementedError()

def refresh_authentication(self):
raise NotImplementedError()

class FormAdapterMixin(object):

Expand All @@ -90,13 +95,14 @@ def format_data_to_request(self, data):
def response_to_native(self, response):
return {'text': response.text}


class JSONAdapterMixin(object):

def get_request_kwargs(self, api_params, *args, **kwargs):
arguments = super(JSONAdapterMixin, self).get_request_kwargs(
api_params, *args, **kwargs)

if 'refresh_auth' in arguments:
del arguments['refresh_auth']

if 'headers' not in arguments:
arguments['headers'] = {}
arguments['headers']['Content-Type'] = 'application/json'
Expand Down
9 changes: 7 additions & 2 deletions tapioca/tapioca.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,13 @@ def _make_request(self, request_method, *args, **kwargs):
data = self._api.process_response(response)
except ResponseProcessException as e:
client = self._wrap_in_tapioca(e.data, response=response,
request_kwargs=request_kwargs)
raise e.tapioca_exception(client=client)
request_kwargs=request_kwargs)
tapioca_exception = e.tapioca_exception(client=client)
if 'refresh_auth' in kwargs and kwargs['refresh_auth'] and self._api.is_authentication_expired(tapioca_exception):
self._api.refresh_authentication()
return self._make_request(request_method, args, kwargs)
else:
raise tapioca_exception

return self._wrap_in_tapioca(data, response=response,
request_kwargs=request_kwargs)
Expand Down
8 changes: 7 additions & 1 deletion tests/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from tapioca.adapters import (
TapiocaAdapter, JSONAdapterMixin,
generate_wrapper_from_adapter)
generate_wrapper_from_adapter)
from tapioca.serializers import SimpleSerializer


Expand All @@ -27,6 +27,7 @@


class TesterClientAdapter(JSONAdapterMixin, TapiocaAdapter):

serializer_class = None
api_root = 'https://api.test.com'
resource_mapping = RESOURCE_MAPPING
Expand All @@ -44,6 +45,11 @@ def get_iterator_next_request_kwargs(self, iterator_request_kwargs,
if url:
return {'url': url}

def is_authentication_expired(self, error):
return error.status_code == 401

def refresh_authentication(self):
pass

TesterClient = generate_wrapper_from_adapter(TesterClientAdapter)

Expand Down
29 changes: 29 additions & 0 deletions tests/test_tapioca.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from tapioca.tapioca import TapiocaClient
from tapioca.serializers import SimpleSerializer
from tapioca.exceptions import ClientError

from tests.client import TesterClient, SerializerClient

Expand Down Expand Up @@ -219,6 +220,34 @@ def test_post_request(self):

self.assertEqual(response().data, {'data': {'key': 'value'}})

@responses.activate
def test_token_expired_and_not_refresh_flag(self):
responses.add(responses.POST, self.wrapper.test().data,
body='{"error": "Token expired"}',
status=401,
content_type='application/json')
with self.assertRaises(ClientError) as context:
response = self.wrapper.test().post()

@responses.activate
def test_token_expired_and_refresh_flag(self):
self.first_call = True
responses.add_callback(
responses.POST, self.wrapper.test().data,
callback=self.request_callback,
content_type='application/json',
)

response = self.wrapper.test().post(refresh_auth=True)

def request_callback(self, request):
if self.first_call:
self.first_call = False
return (401, {'content_type':'application/json'}, json.dumps('{"error": "Token expired"}'))
else:
self.first_call = None
return (201, {'content_type':'application/json'}, json.dumps('{"error": "Token expired"}'))

@responses.activate
def test_put_request(self):
responses.add(responses.PUT, self.wrapper.test().data,
Expand Down

0 comments on commit b9e4b54

Please sign in to comment.