Python Flask-Restful POST not taking JSON arguments
junnytony's answer gave me a hint, and I went ahead with this approach. get_json
seems to have done the trick.
from flask import Flask, jsonify, request
from flask_restful import reqparse, abort, Api, Resource
app = Flask(__name__)
api = Api(app)
#parser = reqparse.RequestParser()
#parser.add_argument('username', type=unicode, location='json')
#parser.add_argument('password', type=unicode, location='json')
class HelloWorld(Resource):
def post(self):
json_data = request.get_json(force=True)
un = json_data['username']
pw = json_data['password']
#args = parser.parse_args()
#un = str(args['username'])
#pw = str(args['password'])
return jsonify(u=un, p=pw)
api.add_resource(HelloWorld, '/testing')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5444 ,debug=True)
I ran into a similar issue and here is a solution that works for me. let's say your application looks like this:
from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
# Define parser and request args
parser = reqparse.RequestParser()
parser.add_argument('last_name', type=str)
parser.add_argument('first_name', type=str)
# not the type=dict
parser.add_argument('personal_data', type=dict)
class Item(Resource):
def post(self):
args = parser.parse_args()
ln = args['last_name']
fn = args['first_name']
# we can also easily parse nested structures
age = args['personal_data']['age']
nn = args['personal_data']['nicknames']
return jsonify(fn=fn, ln=ln, age=age, nn=nn)
api.add_resource(Item, '/item')
if __name__ == '__main__':
app.run(debug=True)
Now, you can easily create some JSON data:
import json
d = {'last_name': 'smith', 'first_name': 'john', 'personal_data': {'age': 18, 'height': 180, 'nicknames': ['johnny', 'grandmaster']}}
print(json.dumps(d, indent=4))
{
"last_name": "smith",
"first_name": "john",
"personal_data": {
"age": 18,
"height": 180,
"nicknames": [
"johnny",
"grandmaster"
]
}
}
json.dumps(d)
'{"last_name": "smith", "first_name": "john", "personal_data": {"age": 18, "height": 180, "nicknames": ["johnny", "grandmaster"]}}'
and call the application:
curl http://localhost:5000/item -d '{"last_name": "smith", "first_name": "john", "personal_data": {"age": 18, "height": 180, "nicknames": ["johnny", "grandmaster"]}}'
This will crash with the error (I shortened the traceback):
age = args['personal_data']['age']
TypeError: 'NoneType' object is not subscriptable
the reason is that the header is not specified. If we add the
-H "Content-Type: application/json"
and then call
curl http://localhost:5000/item -H "Content-Type: application/json" -d '{"last_name": "smith", "first_name": "john", "personal_data": {"age": 18, "height": 180, "nicknames": ["johnny", "grandmaster"]}}'
The output looks as expected:
{
"age": 18,
"fn": "john",
"ln": "smith",
"nn": [
"johnny",
"grandmaster"
]
}
The function can be also further simplified to:
class Item(Resource):
def post(self):
json_data = request.get_json()
# create your response below
as shown above.
According to the documentation for Request.json and the new Request.get_json, you should have the mimetype on your POST request set to application/json
. This is the only way flask will automatically parse your JSON data into the Request.json
property which (I believe) is what Flask-Restful depends on to retrieve JSON data.
NOTE: The newer get_json
function has an option to force the parsing of POST data as JSON irrespective of the mimetype
After forcing the request to parse json, it worked with me. Here is the code:
from flask import Flask, jsonify, request
from flask_restful import reqparse, abort, Api, Resource
app = Flask(__name__)
api = Api(app)
parser = reqparse.RequestParser()
parser.add_argument('username', type=str)
parser.add_argument('password', type=str)
class HelloWorld(Resource):
def post(self):
request.get_json(force=True)
args = parser.parse_args()
un = str(args['username'])
pw = str(args['password'])
return jsonify(u=un, p=pw)
api.add_resource(HelloWorld, '/testing')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5444 ,debug=True)