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?
12 Answers
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 beNone.
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.
3For reference, here's complete code for how to send json from a Python client:
import requests res = requests.post(' 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) 0This 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!
2Assuming 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) 1For 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: "", //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() 1You 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) 1To 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) 0If 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:
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) 