I'm trying to build a simple API using Flask, in which I now want to read some POSTed JSON. I do the POST with the Postman Chrome extension, and the JSON I POST is simply {"text":"lalala"}
. I try to read the JSON using the following method:
@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
content = request.json
print content
return uuid
On the browser it correctly returns the UUID I put in the GET, but on the console, it just prints out None
(where I expect it to print out the {"text":"lalala"}
. Does anybody know how I can get the posted JSON from within the Flask method?
First of all, the .json
attribute is a property that delegates to the request.get_json()
method, which documents why you see None
here.
You need to set the request content type to application/json
for the .json
property and .get_json()
method (with no arguments) to work as either will produce None
otherwise. See the Flask Request
documentation:
This will contain the parsed JSON data if the mimetype indicates JSON (application/json, see is_json()), otherwise it will be None.
You can tell request.get_json()
to skip the content type requirement by passing it the force=True
keyword argument.
Note that if an exception is raised at this point (possibly resulting in a 400 Bad Request response), your JSON data is invalid. It is in some way malformed; you may want to check it with a JSON validator.
For reference, here's complete code for how to send json from a Python client:
import requests
res = requests.post('http://localhost:5000/api/add_message/1234', json={"mytext":"lalala"})
if res.ok:
print(res.json())
The "json=" input will automatically set the content-type, as discussed here: How to POST JSON data with Python Requests?
And the above client will work with this server-side code:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
content = request.json
print(content['mytext'])
return jsonify({"uuid":uuid})
if __name__ == '__main__':
app.run(host= '0.0.0.0',debug=True)
This is the way I would do it and it should be
@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
content = request.get_json(silent=True)
# print(content) # Do your processing
return uuid
With silent=True
set, the get_json
function will fail silently when trying to retrieve the json body. By default this is set to False
. If you are always expecting a json body (not optionally), leave it as silent=False
.
Setting force=True
will ignore the request.headers.get('Content-Type') == 'application/json'
check that flask does for you. By default this is also set to False
.
See flask documentation.
I would strongly recommend leaving force=False
and make the client send the Content-Type
header to make it more explicit.
Hope this helps!
silent=True
. Yes this is possible, and I do use it. Its really based on how you design your API to be consumed. If there is no case like that for your endpoint, just remove silent=True
or explicitly set it to False
.
Assuming you've posted valid JSON with the application/json
content type, request.json
will have the parsed JSON data.
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/echo', methods=['POST'])
def hello():
return jsonify(request.json)
response = request.post('http://127.0.0.1:5000/hello', json={"foo": "bar"})
. Following this running response.json()
should return {'foo': 'bar'}
For all those whose issue was from the ajax call, here is a full example :
Ajax call : the key here is to use a dict
and then JSON.stringify
var dict = {username : "username" , password:"password"};
$.ajax({
type: "POST",
url: "http://127.0.0.1:5000/", //localhost Flask
data : JSON.stringify(dict),
contentType: "application/json",
});
And on server side :
from flask import Flask
from flask import request
import json
app = Flask(__name__)
@app.route("/", methods = ['POST'])
def hello():
print(request.get_json())
return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
if __name__ == "__main__":
app.run()
const foo = {hello: "world"}
.
You may note that request.json
or request.get_json()
works only when the Content-type: application/json
has been added in the header of the request. If you are unable to change the client request configuration, so you can get the body as json like this:
data = json.loads(request.data)
To give another approach.
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route('/service', methods=['POST'])
def service():
data = json.loads(request.data)
text = data.get("text",None)
if text is None:
return jsonify({"message":"text not found"})
else:
return jsonify(data)
if __name__ == '__main__':
app.run(host= '0.0.0.0',debug=True)
If you use force=True
, it will ignore the content type of the request and try to parse the body as JSON regardless.
request.get_json(force=True)
Assuming that you have posted valid JSON,
@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
content = request.json
print content['uuid']
# Return data as JSON
return jsonify(content)
The following codes can be used:
@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
content = request.json['text']
print content
return uuid
Here is a screenshot of me getting the json data:
https://i.stack.imgur.com/2uFqM.jpg
You can see that what is returned is a dictionary type of data.
Even though all the answers I encounter here are right. There is something that I think it should be done as better practice. Here is how I would write it.
from flask import app, request, Flask, jsonify
@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
# Check if the request method is POST
if request.method == 'POST':
# content will return eather parse data as JSON
# Or None incase there is no data
content = request.get_json()
print(content)
# The content could be displayed in html page if serialized as json
return jsonify(content) # Return null if there is content
# if it is only get request then just return uuid
return uuid
Try to set force
attribute as True
in get_json()
method to resolve this issue.
request.get_json(force = True)
Success story sharing