Flask – How do I read the raw body in a POST request when the content type is "application/x-www-form-urlencoded"
Question:
Turns out that Flask sets request.data
to an empty string if the content type of the request is application/x-www-form-urlencoded
. Since I’m using a JSON body request, I just want to parse the json or force Flask to parse it and return request.json
.
This is needed because changing the AJAX content type forces an HTTP OPTION request, which complicates the back-end.
How do I make Flask return the raw data in the request object?
Answers:
You can get the post data via request.form.keys()[0]
if content type is application/x-www-form-urlencoded
.
request.form
is a multidict, whose keys contain the parsed post data.
If you want get the JSON when request is ‘Content-Type’: ‘application/x-www-form-urlencoded’ you need “force” conversion to json like de code below:
from flask import Flask, request
import os
app = Flask(__name__)
@app.route("/my-endpoint", methods = ['POST'])
def myEndpoint():
requestJson = request.get_json(force=True)
//TODO: do something....
return requestJson
if __name__ == "__main__":
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port, debug=True, use_reloader=True)
Use request.get_data()
to get the POST data. This works independent of whether the data has content type application/x-www-form-urlencoded
or application/octet-stream
.
try this:
f = request.form
output = []
user_data = {}
user_data['email'] = f['email']
user_data['password'] = f['password']
user_data['key'] = f['key']
output.append(user_data)
main.py
import json
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['POST'])
def index():
mimetype = request.mimetype
if mimetype == 'application/x-www-form-urlencoded':
form = json.loads(next(iter(request.form.keys())))
elif mimetype == 'multipart/form-data':
form = dict(request.form)
elif mimetype == 'application/json':
form = request.json
else:
form = request.data.decode()
print(mimetype, form, type(form))
return form
if __name__ == '__main__':
app.run()
Test
curl -X POST http://127.0.0.1:5000/ --data "{"a":1, "b":2}"
curl -X POST http://127.0.0.1:5000/ -F a=1 -F b=2
curl -X POST -H "Content-type: application/json" http://127.0.0.1:5000/ --data "{"a":1, "b":2}"
Result
application/x-www-form-urlencoded {'a': 1, 'b': 2} <class 'dict'>
multipart/form-data {'a': '1', 'b': '2'} <class 'dict'>
application/json {'a': 1, 'b': 2} <class 'dict'>
You can get it that way:
@app.route("/path-to-the-post-endpoint", methods=["POST"])
def handle_post_request():
data = request.form.to_dict()
data['some_key_1'] = "Some Value 1"
data['some_key_2'] = "Some Value 2"
# ...etc.
# DO SOMETHING HERE
return [], 200
Turns out that Flask sets request.data
to an empty string if the content type of the request is application/x-www-form-urlencoded
. Since I’m using a JSON body request, I just want to parse the json or force Flask to parse it and return request.json
.
This is needed because changing the AJAX content type forces an HTTP OPTION request, which complicates the back-end.
How do I make Flask return the raw data in the request object?
You can get the post data via request.form.keys()[0]
if content type is application/x-www-form-urlencoded
.
request.form
is a multidict, whose keys contain the parsed post data.
If you want get the JSON when request is ‘Content-Type’: ‘application/x-www-form-urlencoded’ you need “force” conversion to json like de code below:
from flask import Flask, request
import os
app = Flask(__name__)
@app.route("/my-endpoint", methods = ['POST'])
def myEndpoint():
requestJson = request.get_json(force=True)
//TODO: do something....
return requestJson
if __name__ == "__main__":
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port, debug=True, use_reloader=True)
Use request.get_data()
to get the POST data. This works independent of whether the data has content type application/x-www-form-urlencoded
or application/octet-stream
.
try this:
f = request.form
output = []
user_data = {}
user_data['email'] = f['email']
user_data['password'] = f['password']
user_data['key'] = f['key']
output.append(user_data)
main.py
import json
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['POST'])
def index():
mimetype = request.mimetype
if mimetype == 'application/x-www-form-urlencoded':
form = json.loads(next(iter(request.form.keys())))
elif mimetype == 'multipart/form-data':
form = dict(request.form)
elif mimetype == 'application/json':
form = request.json
else:
form = request.data.decode()
print(mimetype, form, type(form))
return form
if __name__ == '__main__':
app.run()
Test
curl -X POST http://127.0.0.1:5000/ --data "{"a":1, "b":2}"
curl -X POST http://127.0.0.1:5000/ -F a=1 -F b=2
curl -X POST -H "Content-type: application/json" http://127.0.0.1:5000/ --data "{"a":1, "b":2}"
Result
application/x-www-form-urlencoded {'a': 1, 'b': 2} <class 'dict'>
multipart/form-data {'a': '1', 'b': '2'} <class 'dict'>
application/json {'a': 1, 'b': 2} <class 'dict'>
You can get it that way:
@app.route("/path-to-the-post-endpoint", methods=["POST"])
def handle_post_request():
data = request.form.to_dict()
data['some_key_1'] = "Some Value 1"
data['some_key_2'] = "Some Value 2"
# ...etc.
# DO SOMETHING HERE
return [], 200