Python Flask-Restful POST not taking JSON arguments
Question:
I am very new to Flask (& Flask-Restful).
My problem : json
arguments for a POST
is getting set to NONE
(not working).
I am able to take arguments from the form-data
, using POSTMAN
plugin for chrome. But, when i switch to raw
(& feed a json
), it fails to read the json & assigns a NONE
to all my arguments.
I have read some related stackoverflow posts related to this : link1, link2, link3 … none of these helped me.
I am using python-2.6
, Flask-Restful-0.3.3
, Flask-0.10.1
, Chrome
, POSTMAN
on Oracle Linux 6.5.
Python code app.py
:
from flask import Flask, jsonify
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):
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)
Testing this using POSTMAN
:
- Using
form-data
: works perfectly !
- Using
raw
-> json
: causes this issue
Things tried #1 :
Add json
parameter to my add_argument()
method in app.py
parser = reqparse.RequestParser()
parser.add_argument('username', type=str, location='json') # added json
parser.add_argument('password', type=str, location='json') # added json
Input
: { “username”: “hello”, “password”: “world” }
Output
: { “p”: “None”, “u”: “None” }
Things tried #2 :
Change type to unicode
in add_argument()
method in app.py
parser = reqparse.RequestParser()
parser.add_argument('username', type=unicode, location='json') # change type to unicode
parser.add_argument('password', type=unicode, location='json') # change type to unicode
Input
: { “username”: “hello”, “password”: “world” }
Output
: { “p”: “None”, “u”: “None” }
PS :
I will keep updating my question, with every failed attempt.
Please let me know if you need any more info to make this question more clear.
Answers:
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
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.
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)
I am very new to Flask (& Flask-Restful).
My problem : json
arguments for a POST
is getting set to NONE
(not working).
I am able to take arguments from the form-data
, using POSTMAN
plugin for chrome. But, when i switch to raw
(& feed a json
), it fails to read the json & assigns a NONE
to all my arguments.
I have read some related stackoverflow posts related to this : link1, link2, link3 … none of these helped me.
I am using python-2.6
, Flask-Restful-0.3.3
, Flask-0.10.1
, Chrome
, POSTMAN
on Oracle Linux 6.5.
Python code app.py
:
from flask import Flask, jsonify
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):
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)
Testing this using POSTMAN
:
- Using
form-data
: works perfectly ! - Using
raw
->json
: causes this issue
Things tried #1 :
Add json
parameter to my add_argument()
method in app.py
parser = reqparse.RequestParser()
parser.add_argument('username', type=str, location='json') # added json
parser.add_argument('password', type=str, location='json') # added json
Input
: { “username”: “hello”, “password”: “world” }
Output
: { “p”: “None”, “u”: “None” }
Things tried #2 :
Change type to unicode
in add_argument()
method in app.py
parser = reqparse.RequestParser()
parser.add_argument('username', type=unicode, location='json') # change type to unicode
parser.add_argument('password', type=unicode, location='json') # change type to unicode
Input
: { “username”: “hello”, “password”: “world” }
Output
: { “p”: “None”, “u”: “None” }
PS :
I will keep updating my question, with every failed attempt.
Please let me know if you need any more info to make this question more clear.
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
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.
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)