How to get POSTed JSON in Flask? - python

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.

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)

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()

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)

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)

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)

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.

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)

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

{
"uuid":1212121212,
"text":"lalala",
"comment":"",
"signed_on":"2022-11-07 00:03:00"
}
you can sent the above data as json and get it in flask application using request.json
from flask import request, Blueprint,flash,json
#app.route('/api/add_message/<uuid>', methods = ["GET", "POST"])
def testing(uuid):
sync_data = request.json
josn_data = json.dumps(sync_data ,default =str)
return josn_data

Try to set force attribute as True in get_json() method to resolve this issue.
request.get_json(force = True)

Related

How can the following issue be resolved in flask? "Method Not Allowed The method is not allowed for the requested URL"

Here is the code
import os
import redis
import flask
import json
import urllib.parse
from flask import Flask, Response, request, render_template, abort
from flask_cors import CORS, cross_origin
#from flask.ext.cors import CORS, cross_origin
app = Flask(__name__)
app.config['CORS_HEADERS'] = 'Content-Type'
redis_handle = redis.Redis('localhost')
requiredFields = ("id", "title", "name") # fields required for user object
#app.route('/')
#cross_origin()
def hello():
return 'Hello World!'
#app.route('/users/<user_id>', methods=['GET'])
#cross_origin()
def get_user(user_id):
response = {}
# user_id = request.args.get("id")
user = redis_handle.get(user_id)
if not user:
response["msg"] = "no user found"
return Response(json.dumps(response), status=404, mimetype="application/json")
return user
#app.route('/users', methods=['POST'])
#cross_origin()
def save_user():
data = request.get_json(force=True)
response = {}
if all(field in data for field in requiredFields):
redis_handle.set(data["id"], json.dumps(data))
return Response(status=201)
else:
missing_key = str([val for val in requiredFields if val not in dict(data).keys()])
response["msg"] = "required key " + missing_key + " not found"
return Response(json.dumps(response), status=400)
#app.route('/users/<user_id>', methods=['DELETE'])
#cross_origin()
def delete_user(user_id):
response = {}
resp = redis_handle.delete(user_id)
if resp == 0:
response["msg"] = "no such entity found"
status = 404
else:
response["msg"] = "Delete op is successful"
status = 200
return Response(json.dumps(response), status=status)
#app.route('/clear', methods=['GET'])
#cross_origin()
def clear_data():
redis_handle.flushall()
return "ok!"
if __name__ == "__main__":
app.run(debug=True)
As of my knowledge, I have even included the method = "POST" as well but still don't know what is going wrong.
I tried to create a small crud application using redis, python, flask but couldn't encountering this issue. Can someone tell me where and what am I doing wrong?
Browsers don't run POST methods outside of a <form> entry or AJAX function. Therefore, you're running a GET, which "isn't allowed".
Unclear what you expected, but to see all users, you'll need to edit your route to first add the GET method, then if so, return a response that returns/renders all users rather than checking the request json body, which won't exist for GET requests
If you only wanted to get one user, edit the url to include the user ID
The browser will use the GET method for URLs that you input in URL/search bar but you don't have any function decorated with #app.route('/users', methods=['GET']).
If you want to create a user with POST /users then it would be easier to use some HTTP client like https://www.postman.com, https://insomnia.rest, etc. or even fetch in the browser's console.

Request body returning None in google function [duplicate]

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.
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)
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()
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)
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)
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.
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)
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
{
"uuid":1212121212,
"text":"lalala",
"comment":"",
"signed_on":"2022-11-07 00:03:00"
}
you can sent the above data as json and get it in flask application using request.json
from flask import request, Blueprint,flash,json
#app.route('/api/add_message/<uuid>', methods = ["GET", "POST"])
def testing(uuid):
sync_data = request.json
josn_data = json.dumps(sync_data ,default =str)
return josn_data
Try to set force attribute as True in get_json() method to resolve this issue.
request.get_json(force = True)

Print JSON Data in output within FLASK [duplicate]

This question already has an answer here:
Print JSON Data - Flask [closed]
(1 answer)
Closed 6 years ago.
So I have this test app (learning flask). It takes a username and a message input and displays it on the third page. The last "return" below spits out that data. I need to include the JSON equivalent of the data below it. I think I need to put 'username' and 'message' into a variable and call json dumps to return it also? killing myself over here.
from flask import Flask, render_template, request,
redirect, url_for,abort, session
import json
from json import dumps
app = Flask(__name__)
app.config['SECRET_KEY'] = 'F34TF$($e34D';
#app.route('/')
def home():
return render_template('index.html')
#app.route('/signup', methods=['POST'])
def signup():
session['username'] = request.form['username']
session['message'] = request.form['message']
return redirect(url_for('message'))
#app.route('/message')
def message():
if not 'username' in session:
return abort(403)
return render_template('message.html',
username=session['username'],message=session['message']),
if __name__ == '__main__':
app.run()
This is what you need. The page also has example. You can do something like below. Normally you would want to respond with either a html or json depending on the accept header. It defines what data the client is expecting.
If accept is 'application/json' use jsonify. if accept is 'text/html', then render your template. That way your page will be normal when loaded from browser, however when using a restclient with accept headers set appropriately, you get json responses.
from flask import request
#app.route('/message')
def message():
if not 'username' in session:
return abort(403)
if request.headers['accept'] == 'text/html':
return render_template('message.html',
username=session['username'],message=session['message'])
elif request.headers['accept'] == 'application/json':
return jsonify(
username=session['username'], message=session['message'])

Unable to read POSTed application/json data in Flask

I have a flask app which has one endpoint as:
#app.route('/restaurant/<restaurant_id>', methods=['GET', 'POST'])
def detail(restaurant_id=None):
if request.method == 'GET':
#something
elif request.method == 'POST':
print jsonify(request.get_json(force=True)) #This doesn't work if I set content type as applicaiton/json
comments = [request.form['comment']] #this works if I set content type as form-data
# something
return Response(json.dumps({
'success': True,
'response': json_docs
}), status=200, content_type='application/json')
For some reason, I'm unable to read the POSTed data when it is posted as a JSON with application/json as the Content-Type. The print command just returns None. How do I read the Json data?
request.get_json() returns JSON, so jsonify should turn it back into JSON. And comments should be request.get_json(force=True). Hope this helps.

Flask-restful: How to only response to requests come with ('Accept':'application/json')?

I have a json api APP, working well.Now I want it only accept and response json, not response to text/html request.
App looks like this:
class Books(Resource):
def get(self):
return json.dumps(data)
Someone can help?
Thanks.
You could use a preprocessing request handler to reject all request with the wrong MimeType. There is a property of the Request object (not documented tought, but present at least on Flask 0.10) named is_json
Given your Flask app is called application, you could use something like :
from flask import request, abort, jsonify
#application.before_request
def only_json():
if not request.is_json:
abort(400) # or any custom BadRequest message
I would also use the Flask jsonify function to build your reponse, it will ensure that the response is well formatted in json, and also sets the right headers.
class Books(Resource):
def get(self):
return jsonify(data)

Categories