summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Petrello <lists@ryanpetrello.com>2014-09-23 10:35:37 -0400
committerRyan Petrello <lists@ryanpetrello.com>2014-09-25 15:17:40 -0400
commit921a8b77dcb11d4e3668bf23a5731b665b748a92 (patch)
tree8ea2d6d17761068e2799ad1a698d236f5919ccf5
parente756446ab65f24f335e46e95da4c7e71021be2ad (diff)
downloadpecan-921a8b77dcb11d4e3668bf23a5731b665b748a92.tar.gz
For HTTP POSTs, map JSON request bodies to controller keyword arguments.
Fixes-bug: 1336943 Change-Id: I2e59e5d43d87a5279c41b155188ebe3281de0e11
-rw-r--r--pecan/core.py9
-rw-r--r--pecan/tests/test_base.py98
2 files changed, 107 insertions, 0 deletions
diff --git a/pecan/core.py b/pecan/core.py
index fc0468e..934931a 100644
--- a/pecan/core.py
+++ b/pecan/core.py
@@ -14,6 +14,7 @@ import six
from webob import (Request as WebObRequest, Response as WebObResponse, exc,
acceptparse)
+from webob.multidict import NestedMultiDict
from .compat import urlparse, unquote_plus, izip
from .secure import handle_security
@@ -499,6 +500,14 @@ class PecanBase(object):
# fetch any parameters
if req.method == 'GET':
params = dict(req.GET)
+ elif req.content_type in ('application/json',
+ 'application/javascript'):
+ try:
+ if not isinstance(req.json, dict):
+ raise TypeError('%s is not a dict' % req.json)
+ params = dict(NestedMultiDict(req.GET, req.json))
+ except (TypeError, ValueError):
+ params = dict(req.params)
else:
params = dict(req.params)
diff --git a/pecan/tests/test_base.py b/pecan/tests/test_base.py
index e6ddb05..b22b2c8 100644
--- a/pecan/tests/test_base.py
+++ b/pecan/tests/test_base.py
@@ -440,6 +440,16 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('index: 4')
+ def test_explicit_json_kwargs(self):
+ r = self.app_.post_json('/', {'id': '4'})
+ assert r.status_int == 200
+ assert r.body == b_('index: 4')
+
+ def test_path_with_explicit_json_kwargs(self):
+ r = self.app_.post_json('/4', {'id': 'four'})
+ assert r.status_int == 200
+ assert r.body == b_('index: 4')
+
def test_multiple_kwargs(self):
r = self.app_.get('/?id=5&dummy=dummy')
assert r.status_int == 200
@@ -450,6 +460,11 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('index: 6')
+ def test_json_kwargs_from_root(self):
+ r = self.app_.post_json('/', {'id': '6', 'dummy': 'dummy'})
+ assert r.status_int == 200
+ assert r.body == b_('index: 6')
+
# multiple args
def test_multiple_positional_arguments(self):
@@ -477,6 +492,11 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('multiple: five, six')
+ def test_positional_args_with_json_kwargs(self):
+ r = self.app_.post_json('/multiple', {'one': 'five', 'two': 'six'})
+ assert r.status_int == 200
+ assert r.body == b_('multiple: five, six')
+
def test_positional_args_with_url_encoded_dictionary_kwargs(self):
r = self.app_.post('/multiple', {'one': 'Five%20', 'two': 'Six%20%21'})
assert r.status_int == 200
@@ -527,6 +547,11 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('optional: 4')
+ def test_optional_arg_with_json_kwargs(self):
+ r = self.app_.post_json('/optional', {'id': '4'})
+ assert r.status_int == 200
+ assert r.body == b_('optional: 4')
+
def test_optional_arg_with_url_encoded_kwargs(self):
r = self.app_.post('/optional', {'id': 'Some%20Number'})
assert r.status_int == 200
@@ -537,6 +562,11 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('optional: 5')
+ def test_multiple_positional_arguments_with_json_kwargs(self):
+ r = self.app_.post_json('/optional/5', {'id': 'five'})
+ assert r.status_int == 200
+ assert r.body == b_('optional: 5')
+
def test_multiple_positional_url_encoded_arguments_with_kwargs(self):
r = self.app_.post('/optional/Some%20Number', {'id': 'five'})
assert r.status_int == 200
@@ -557,6 +587,11 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('optional: 7')
+ def test_optional_arg_with_multiple_json_kwargs(self):
+ r = self.app_.post_json('/optional', {'id': '7', 'dummy': 'dummy'})
+ assert r.status_int == 200
+ assert r.body == b_('optional: 7')
+
def test_optional_arg_with_multiple_url_encoded_dictionary_kwargs(self):
r = self.app_.post('/optional', {
'id': 'Some%20Number',
@@ -621,6 +656,11 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('multiple_optional: 1, None, None')
+ def test_multiple_optional_positional_args_with_json_kwargs(self):
+ r = self.app_.post_json('/multiple_optional', {'one': '1'})
+ assert r.status_int == 200
+ assert r.body == b_('multiple_optional: 1, None, None')
+
def test_multiple_optional_positional_args_with_encoded_dict_kwargs(self):
r = self.app_.post('/multiple_optional', {'one': 'One%21'})
assert r.status_int == 200
@@ -631,6 +671,11 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('multiple_optional: 1, None, None')
+ def test_multiple_optional_positional_args_and_json_kwargs(self):
+ r = self.app_.post_json('/multiple_optional/1', {'one': 'one'})
+ assert r.status_int == 200
+ assert r.body == b_('multiple_optional: 1, None, None')
+
def test_multiple_optional_encoded_positional_args_and_dict_kwargs(self):
r = self.app_.post('/multiple_optional/One%21', {'one': 'one'})
assert r.status_int == 200
@@ -656,6 +701,14 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('multiple_optional: 1, 2, 3')
+ def test_multiple_optional_args_with_multiple_json_kwargs(self):
+ r = self.app_.post_json(
+ '/multiple_optional',
+ {'one': '1', 'two': '2', 'three': '3', 'four': '4'}
+ )
+ assert r.status_int == 200
+ assert r.body == b_('multiple_optional: 1, 2, 3')
+
def test_multiple_optional_args_with_multiple_encoded_dict_kwargs(self):
r = self.app_.post(
'/multiple_optional',
@@ -709,6 +762,14 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('variable_args: ')
+ def test_variable_args_with_json_kwargs(self):
+ r = self.app_.post_json(
+ '/variable_args',
+ {'id': '3', 'dummy': 'dummy'}
+ )
+ assert r.status_int == 200
+ assert r.body == b_('variable_args: ')
+
def test_variable_kwargs(self):
r = self.app_.get('/variable_kwargs')
assert r.status_int == 200
@@ -735,6 +796,14 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('variable_kwargs: dummy=dummy, id=3')
+ def test_multiple_variable_kwargs_with_json_kwargs(self):
+ r = self.app_.post_json(
+ '/variable_kwargs',
+ {'id': '3', 'dummy': 'dummy'}
+ )
+ assert r.status_int == 200
+ assert r.body == b_('variable_kwargs: dummy=dummy, id=3')
+
def test_multiple_variable_kwargs_with_encoded_dict_kwargs(self):
r = self.app_.post(
'/variable_kwargs',
@@ -779,6 +848,14 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('variable_all: 6, day=12, month=1')
+ def test_variable_post_with_json_kwargs(self):
+ r = self.app_.post_json(
+ '/variable_all/6',
+ {'month': '1', 'day': '12'}
+ )
+ assert r.status_int == 200
+ assert r.body == b_('variable_all: 6, day=12, month=1')
+
def test_variable_post_mixed(self):
r = self.app_.post(
'/variable_all/7',
@@ -787,6 +864,14 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('variable_all: 7, day=12, id=seven, month=1')
+ def test_variable_post_mixed_with_json(self):
+ r = self.app_.post_json(
+ '/variable_all/7',
+ {'id': 'seven', 'month': '1', 'day': '12'}
+ )
+ assert r.status_int == 200
+ assert r.body == b_('variable_all: 7, day=12, id=seven, month=1')
+
def test_no_remainder(self):
try:
r = self.app_.get('/eater')
@@ -843,6 +928,11 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('eater: 9, None, day=12, month=1')
+ def test_post_remainder_with_json_kwargs(self):
+ r = self.app_.post_json('/eater/9', {'month': '1', 'day': '12'})
+ assert r.status_int == 200
+ assert r.body == b_('eater: 9, None, day=12, month=1')
+
def test_post_many_remainders_with_many_kwargs(self):
r = self.app_.post(
'/eater/10',
@@ -851,6 +941,14 @@ class TestControllerArguments(PecanTestCase):
assert r.status_int == 200
assert r.body == b_('eater: 10, dummy, day=12, month=1')
+ def test_post_many_remainders_with_many_json_kwargs(self):
+ r = self.app_.post_json(
+ '/eater/10',
+ {'id': 'ten', 'month': '1', 'day': '12', 'dummy': 'dummy'}
+ )
+ assert r.status_int == 200
+ assert r.body == b_('eater: 10, dummy, day=12, month=1')
+
class TestDefaultErrorRendering(PecanTestCase):