Accessing incoming POST data in Flask
You're inadvertently sending the wrong Content Type.
By default, curl
's -d
flag will send POST data with content-type application/x-www-form-urlencoded
. Since you're not sending data in the format that it's expecting (key=value), it's dropping the data altogether. For JSON data, you'll need to send the HTTP request with the content-type set to application/json
like so:
curl -XPOST -H "Content-Type: application/json" 'http://127.0.0.1:5000/?thing1=1' -d '{"thing2":2}'
Also, flask's request.form
field only contains POST form data, not other content types. You can access the raw POST request body with request.data
or, more convenienty, the parsed JSON data using request.get_json
.
Below is a fixed version of your example:
from flask import Flask, request
import json
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def refresh():
params = {
'thing1': request.values.get('thing1'),
'thing2': request.get_json().get('thing2')
}
return json.dumps(params)
app.run()
UPDATE: I misspoke earlier - request.body
should actually be request.data
. Also as it turns out request.json
is deprecated and request.get_json
should be used now instead. The original post has been updated.
Narfanator
Updated on July 30, 2022Comments
-
Narfanator almost 2 years
Here's the flask code:
from flask import Flask, request import json app = Flask(__name__) @app.route('/', methods=['GET', 'POST']) def refresh(): params = { 'thing1': request.values.get('thing1'), 'thing2': request.values.get('thing2') } return json.dumps(params)
Here's the
cURL
:$ curl -XGET 'http://127.0.0.1:5000/?thing1=1' -d '{"thing2":2}' > {"thing1": "1", "thing2": null} $ curl -XGET 'http://127.0.0.1:5000/?thing1=1' -d '{"thing2":2}' > {"thing1": "1", "thing2": null}
The docs seem VERY clear that this should be working:
form
A MultiDict with the parsed form data from POST or PUT requests. Please keep in mind that file uploads will not end up here, but instead in the files attribute.
args
A MultiDict with the parsed contents of the query string. (The part in the URL after the question mark).
values
A CombinedMultiDict with the contents of both form and args.
Any ideas what I'm doing wrong?
Update: Trying suggestions from one of the answers, swapping out the
return
line:Using
return json.dumps(json.load(request.body.decode("utf-8") ))
generates the errorAttributeError: 'Request' object has no attribute 'body'
Using
return json.dumps(json.load(request.json))
generates the errorAttributeError: 'NoneType' object has no attribute 'read'
Using
POST
with the origin code appears to have no effect:$ curl -XPOST 'http://127.0.0.1:5000/?thing1=1' -d '{"thing2":2}' {"thing1": "1", "thing2": null}
Setting the content type and using
POST
with the original code also has no apparent effect:$ curl -XPOST -H "Content-Type: application/json" 'http://127.0.0.1:5000/?thing1=1' -d '{"thing2":2}' {"thing1": "1", "thing2": null}
although I went and verified that the content-type was then correctly set:
... print(request.headers) ... Host: 127.0.0.1:5000 User-Agent: curl/7.54.0 Accept: */* Content-Type: application/json Content-Length: 12