Browse Source

Added request.get_json().

pull/764/merge
Armin Ronacher 12 years ago
parent
commit
964174931d
  1. 2
      CHANGES
  2. 9
      flask/testsuite/helpers.py
  3. 61
      flask/wrappers.py

2
CHANGES

@ -77,6 +77,8 @@ Release date to be decided.
- Added `appcontext_pushed` and `appcontext_popped` signals. - Added `appcontext_pushed` and `appcontext_popped` signals.
- The builtin run method now takes the ``SERVER_NAME`` into account when - The builtin run method now takes the ``SERVER_NAME`` into account when
picking the default port to run on. picking the default port to run on.
- Added `flask.request.get_json()` as a replacement for the old
`flask.request.json` property.
Version 0.9 Version 0.9
----------- -----------

9
flask/testsuite/helpers.py

@ -33,7 +33,7 @@ class JSONTestCase(FlaskTestCase):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@app.route('/json', methods=['POST']) @app.route('/json', methods=['POST'])
def return_json(): def return_json():
return flask.jsonify(foo=text_type(flask.request.json)) return flask.jsonify(foo=text_type(flask.request.get_json()))
c = app.test_client() c = app.test_client()
rv = c.post('/json', data='malformed', content_type='application/json') rv = c.post('/json', data='malformed', content_type='application/json')
self.assert_equal(rv.status_code, 400) self.assert_equal(rv.status_code, 400)
@ -43,7 +43,7 @@ class JSONTestCase(FlaskTestCase):
app.testing = True app.testing = True
@app.route('/') @app.route('/')
def index(): def index():
return flask.request.json return flask.request.get_json()
c = app.test_client() c = app.test_client()
resp = c.get('/', data=u'"Hällo Wörld"'.encode('iso-8859-15'), resp = c.get('/', data=u'"Hällo Wörld"'.encode('iso-8859-15'),
@ -82,7 +82,8 @@ class JSONTestCase(FlaskTestCase):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@app.route('/add', methods=['POST']) @app.route('/add', methods=['POST'])
def add(): def add():
return text_type(flask.request.json['a'] + flask.request.json['b']) json = flask.request.get_json()
return text_type(json['a'] + json['b'])
c = app.test_client() c = app.test_client()
rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}), rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}),
content_type='application/json') content_type='application/json')
@ -127,7 +128,7 @@ class JSONTestCase(FlaskTestCase):
app.json_decoder = MyDecoder app.json_decoder = MyDecoder
@app.route('/', methods=['POST']) @app.route('/', methods=['POST'])
def index(): def index():
return flask.json.dumps(flask.request.json['x']) return flask.json.dumps(flask.request.get_json()['x'])
c = app.test_client() c = app.test_client()
rv = c.post('/', data=flask.json.dumps({ rv = c.post('/', data=flask.json.dumps({
'x': {'_foo': 42} 'x': {'_foo': 42}

61
flask/wrappers.py

@ -10,7 +10,6 @@
""" """
from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase
from werkzeug.utils import cached_property
from werkzeug.exceptions import BadRequest from werkzeug.exceptions import BadRequest
from .debughelpers import attach_enctype_error_multidict from .debughelpers import attach_enctype_error_multidict
@ -18,6 +17,16 @@ from . import json
from .globals import _request_ctx_stack from .globals import _request_ctx_stack
_missing = object()
def _get_data(req, cache):
getter = getattr(req, 'get_data', None)
if getter is not None:
return getter(cache=cache)
return req.data
class Request(RequestBase): class Request(RequestBase):
"""The request object used by default in Flask. Remembers the """The request object used by default in Flask. Remembers the
matched endpoint and view arguments. matched endpoint and view arguments.
@ -88,24 +97,60 @@ class Request(RequestBase):
if self.url_rule and '.' in self.url_rule.endpoint: if self.url_rule and '.' in self.url_rule.endpoint:
return self.url_rule.endpoint.rsplit('.', 1)[0] return self.url_rule.endpoint.rsplit('.', 1)[0]
@cached_property @property
def json(self): def json(self):
"""If the mimetype is `application/json` this will contain the """If the mimetype is `application/json` this will contain the
parsed JSON data. Otherwise this will be `None`. parsed JSON data. Otherwise this will be `None`.
The :meth:`get_json` method should be used instead.
"""
# XXX: deprecate property
return self.get_json()
def get_json(self, force=False, silent=False, cache=True):
"""Parses the incoming JSON request data and returns it. If
parsing fails the :meth:`on_json_loading_failed` method on the
request object will be invoked. By default this function will
only load the json data if the mimetype is ``application/json``
but this can be overriden by the `force` parameter.
:param force: if set to `True` the mimetype is ignored.
:param silent: if set to `False` this method will fail silently
and return `False`.
:param cache: if set to `True` the parsed JSON data is remembered
on the request.
""" """
if self.mimetype == 'application/json': rv = getattr(self, '_cached_json', _missing)
if rv is not _missing:
return rv
if self.mimetype != 'application/json' and not force:
return None
# We accept a request charset against the specification as
# certain clients have been using this in the past. This
# fits our general approach of being nice in what we accept
# and strict in what we send out.
request_charset = self.mimetype_params.get('charset') request_charset = self.mimetype_params.get('charset')
try: try:
data = _get_data(self, cache)
if request_charset is not None: if request_charset is not None:
return json.loads(self.data, encoding=request_charset) rv = json.loads(data, encoding=request_charset)
return json.loads(self.data) else:
rv = json.loads(data)
except ValueError as e: except ValueError as e:
return self.on_json_loading_failed(e) if silent:
rv = None
else:
rv = self.on_json_loading_failed(e)
if cache:
self._cached_json = rv
return rv
def on_json_loading_failed(self, e): def on_json_loading_failed(self, e):
"""Called if decoding of the JSON data failed. The return value of """Called if decoding of the JSON data failed. The return value of
this method is used by :attr:`json` when an error occurred. The default this method is used by :meth:`get_json` when an error occurred. The
implementation just raises a :class:`BadRequest` exception. default implementation just raises a :class:`BadRequest` exception.
.. versionchanged:: 0.10 .. versionchanged:: 0.10
Removed buggy previous behavior of generating a random JSON Removed buggy previous behavior of generating a random JSON

Loading…
Cancel
Save