0

I have a python flask-restful app which receives json in the post body. Here the two minimal files app.py and info.py:

The application module app.py:

from flask import Flask
from flask_restful import Resource, Api, reqparse

flaskApp = Flask(__name__)
api = Api(flaskApp)

from endpoints.info import Info

api.add_resource(Infp, '/v1/info')

The endpoint module info.py (in subfolder endpoints):

from flask_restful import Resource, reqparse

myParser = reqparse.RequestParser()
reqparse.RequestParser.
myParser.add_argument('argA', location='json')
myParser.add_argument('argB', location='json')


class Info(Resource):

    def post(self):
        args = myParser.parse_args()
        return args

This app works correct when I send a request as mime type application/json:

curl  -s "http://127.0.0.1:5000/v1/info" -d '{"locality":"Barton"}' -H Content-Type:application/json

returns as expected:

{
    "locality": "Barton"
}

However the client will send the requests as the normal url-encoded mimetype. When I just do

curl  -s "http://127.0.0.1:5000/v1/info" -d '{"locality":"Barton"}'

the app returns {} So it did not interpret the body as intended.

How can I force the app to interpret the post body as json regardsless of the request's mime-type?

I know about this StackOverflow question; it suggests usingRequest.get_json. But how can I access this method in the Resource class Info to feed it into myParser?

Community
  • 1
  • 1
halloleo
  • 9,216
  • 13
  • 64
  • 122
  • One could give the argument, that such a request would be invalid. – Klaus D. Jul 15 '16 at 06:59
  • You can use `request.get_json(force=True)`, refer to the [docs](http://flask.pocoo.org/docs/0.11/api/#flask.Request.get_json) for more detail. – alexpeits Jul 15 '16 at 07:16

1 Answers1

2

According to the flask-restful docs, the location keyword argument of add_argument indicates a property of flask.Request from which to pull the argument.

According to the Flask docs, the json property will be empty if the mimetype of the request is not application/json.

But if you use Request.get_json(force=True) directly, you don't need the parser. You can just access the value:

from flask import request
class Info(Resource):
    def post(self):
        data = request.get_json(force=True)
        return data['locality']
halloleo
  • 9,216
  • 13
  • 64
  • 122
A. Vidor
  • 2,502
  • 1
  • 16
  • 24
  • Thanks for this. I will try it out on Monday. :-) – halloleo Jul 15 '16 at 14:01
  • @halloleo Let us know whether the `type` argument really does accept arbitrary casting functions! The documentation is pretty terse on that point. – A. Vidor Jul 16 '16 at 02:15
  • Yep, this works. Thanks a million.:-) Obviously I have to implement the filtering, done previously by `RequestParser` myself after receiving the arguments in `data`. – halloleo Jul 20 '16 at 02:34
  • @halloleo Did you try passing `location='data'` and `type=lambda x:json.loads(x)` to `add_argument`? – A. Vidor Jul 20 '16 at 02:48
  • 1
    No, no, I went for the `get_json` solution. When I try the RequestParser solution via `add_argument(p, location='data', type=lambda x:json.loads(x))` I get: "AttributeError: 'str' object has no attribute 'get'". – halloleo Jul 20 '16 at 03:14
  • @halloleo That makes sense; the `type` function casts the "got" value, not the data structure to "get" it from. Rats. – A. Vidor Jul 20 '16 at 03:19