Skip to content

Commit 58f116e

Browse files
committed
Add Flask response wrapper
1 parent 67d78ac commit 58f116e

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

hypermedia_resource/wrappers.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from negotiator import ContentNegotiator, AcceptParameters, ContentType
22
from .resource import HypermediaResource
33

4+
try:
5+
from flask import Response
6+
except:
7+
pass
8+
49
class HypermediaResponse(object):
510

611
def __init__(self, media_type, resource):
@@ -20,3 +25,51 @@ def build(self, resource, accept):
2025
if negotiate:
2126
return HypermediaResponse(str(negotiate.content_type), resource)
2227
return HypermediaResponse(self.default_type, resource)
28+
29+
class APIResource(object):
30+
31+
def default_type(self):
32+
return "application/hal+json"
33+
34+
def available_actions(self):
35+
return [action for action in self.actions().values()
36+
if hasattr(self, action)]
37+
38+
def available_methods(self):
39+
return [method for method, action in self.actions().items()
40+
if action in self.available_actions()]
41+
42+
def method_override(self):
43+
return "_method"
44+
45+
def actions(self):
46+
"""Defaults Actions"""
47+
return {
48+
'GET': 'read',
49+
'POST': 'process',
50+
'PATCH': 'partial',
51+
'PUT': 'save',
52+
'DELETE': 'remove'
53+
}
54+
55+
def build_response(self, resource, accepts):
56+
response_builder = ResponseBuilder(self.default_type())
57+
return response_builder.build(resource, accepts)
58+
59+
class FlaskAPIResource(APIResource):
60+
61+
def get_method(self, request):
62+
if request.method != "POST":
63+
return request.method
64+
method_override = self.method_override()
65+
if request.form.has_key(method_override) and request.method == "POST":
66+
return request.form[method_override]
67+
return request.method
68+
69+
def response_for(self, request):
70+
method = self.get_method(request)
71+
action_name = self.actions()[method]
72+
action = getattr(self, action_name)
73+
resource = action(request)
74+
response = self.build_response(resource, request.headers.get('Accept'))
75+
return Response(response.body, mimetype=response.media_type)

tests/wrappers_test.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import unittest
2-
from mock import Mock
2+
from mock import Mock, patch
33
from hypermedia_resource import HypermediaResource
44
from hypermedia_resource.wrappers import HypermediaResponse, ResponseBuilder
5+
from hypermedia_resource.wrappers import APIResource, FlaskAPIResource
56

67
def adapter():
78
adapter = Mock()
@@ -10,6 +11,15 @@ def adapter():
1011
adapter.build.return_value = "built"
1112
return adapter
1213

14+
def request(method='GET', data={}):
15+
request = Mock()
16+
request.method = method
17+
request.data = data
18+
request.headers = Mock()
19+
request.headers.get = Mock()
20+
request.headers.get.return_value = "application/hal+json"
21+
return request
22+
1323
class TestHypermediaResponse(unittest.TestCase):
1424

1525
def test(self):
@@ -29,3 +39,64 @@ def test(self):
2939
response = response_builder.build(resource, accept)
3040
self.assertEqual(response.media_type, "application/hal+json")
3141
self.assertEqual(response.body, "built")
42+
43+
class TestAPIResource(unittest.TestCase):
44+
45+
def setUp(self):
46+
HypermediaResource.adapters.add(adapter())
47+
self.resource = APIResource()
48+
49+
def test_available_actions(self):
50+
self.resource.read = Mock()
51+
actions = self.resource.available_actions()
52+
self.assertTrue('read' in actions)
53+
self.assertFalse('missing' in actions)
54+
55+
def test_available_methods(self):
56+
self.resource.read = Mock()
57+
methods = self.resource.available_methods()
58+
self.assertTrue('GET' in methods)
59+
self.assertFalse('POST' in methods)
60+
61+
def test_response(self):
62+
resource = HypermediaResource()
63+
self.resource.read = Mock()
64+
self.resource.read.return_value = resource
65+
accepts = "application/hal+json"
66+
response = self.resource.build_response(resource, accepts)
67+
self.assertEqual(response.body, "built")
68+
69+
class TestFlaskAPIResource(unittest.TestCase):
70+
71+
def setUp(self):
72+
self.resource = FlaskAPIResource()
73+
74+
def test_get_method(self):
75+
method = self.resource.get_method(request("GET"))
76+
self.assertEqual(method, "GET")
77+
78+
def test_get_method_override(self):
79+
method = self.resource.get_method(request("POST", { "_method": "PUT"}))
80+
self.assertEqual(method, "PUT")
81+
82+
@patch('hypermedia_resource.wrappers.Response')
83+
def test_response_for(self, mock_method):
84+
resource = HypermediaResource()
85+
86+
# Response
87+
response = Mock()
88+
response.body = "body"
89+
response.media_type = "media_type"
90+
91+
# Read action
92+
self.resource.read = Mock()
93+
self.resource.read.return_value = resource
94+
95+
# Mock build response
96+
self.resource.build_response = Mock()
97+
self.resource.build_response.return_value = response
98+
99+
self.resource.response_for(request())
100+
self.resource.build_response.assert_called_with(resource, "application/hal+json")
101+
mock_method.assert_called_with(response.body, mimetype=response.media_type)
102+

0 commit comments

Comments
 (0)