For HTTP POSTs, map JSON request bodies to controller keyword arguments.

Fixes-bug: 1336943
Change-Id: I2e59e5d43d87a5279c41b155188ebe3281de0e11
This commit is contained in:
Ryan Petrello
2014-09-23 10:35:37 -04:00
parent e756446ab6
commit 921a8b77dc
2 changed files with 107 additions and 0 deletions

View File

@@ -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)

View File

@@ -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):