Reputation: 155
I was following this tutorial and it was going pretty well. He then introduced reqparse
and I followed along. I tried to test my code and I get this error
{'message': "Did not attempt to load JSON data because the request Content-Type was not 'application/json'."}
I don't know if I'm missing something super obvious but I'm pretty sure I copied his code exactly. here's the code:
main.py
from flask import Flask, request
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
#basic get and post
names = {"sai": {"age": 19, "gender": "male"},
"bill": {"age": 23, "gender": "male"}}
class HelloWorld(Resource):
def get(self, name, numb):
return names[name]
def post(self):
return {"data": "Posted"}
api.add_resource(HelloWorld, "/helloworld/<string:name>/<int:numb>")
# getting larger data
pictures = {}
class picture(Resource):
def get(self, picture_id):
return pictures[picture_id]
def put(self, picture_id):
print(request.form['likes'])
pass
api.add_resource(picture, "/picture/<int:picture_id>")
# reqparse
video_put_args = reqparse.RequestParser() # make new request parser object to make sure it fits the correct guidelines
video_put_args.add_argument("name", type=str, help="Name of the video")
video_put_args.add_argument("views", type=int, help="Views on the video")
video_put_args.add_argument("likes", type=int, help="Likes on the video")
videos = {}
class Video(Resource):
def get(self, video_id):
return videos[video_id]
def post(self, video_id):
args = video_put_args.parse_args()
print(request.form['likes'])
return {video_id: args}
api.add_resource(Video, "/video/<int:video_id>")
if __name__ == "__main__":
app.run(debug=True)
test_rest.py
import requests
BASE = "http://127.0.0.1:5000/"
response = requests.post(BASE + 'video/1', {"likes": 10})
print(response.json())
Upvotes: 9
Views: 25120
Reputation: 2182
Use flask==2.0.0
and werkzeug==2.0.0
, use seperate docker container if possible.
Upvotes: 0
Reputation: 21
pip install -r requirements.txt
file requirements.txt such as:
-> I think this error was Flask version > 2.0. If you use Flask version > 2.0 you add location ='form':
ex: parse.add_argument('ID', location='form')
Upvotes: 0
Reputation: 91
I've faced with similar trouble. I've got error about content type, but in flask-restx. My conclusion is to use reqparse to define required parameters, and also for getting this parameters, other way you'll get the same error.
I've used reqparse to define file_uploader, and api.payload, to get other data
upload_parser = api.parser()
upload_parser.add_argument('file', location='files',
type=FileStorage, required=True)
hostauth_create_fields = api.model(
'HostAuthCreate', {
'name': fields.String(description="The name of the instance", required=True),
'username': fields.String(description="Username to connect", required=True),
'password': fields.String(description="Password to connect", required=False)
}
)
@api.route('/api/hostauth')
class HostAuthView(Resource):
@api.expect(upload_parser, hostauth_create_fields)
def post(self):
args = upload_parser.parse_args()
args.get('file')
api.payload.get('name') # This line will cause a error
return {'name': args.get('name')}, 201
But that's possible to parse all args via upload_parser:
upload_parser = api.parser()
upload_parser.add_argument('file', location='files',
type=FileStorage, required=True)
upload_parser.add_argument('name', type=str, required=True, location="form")
upload_parser.add_argument('username', type=str, required=True, location="form")
upload_parser.add_argument('password', type=str, location="form")
And to get other params, use:
args.get('name')
Possibly api.model rewrites header that responsible for accepted content type set by reqparse. So you should choose reqparse if you have files as args. In other routes you can use api.model again
Upvotes: 0
Reputation: 61
azzamsa is correct. I could add the following : if your API worked and suddenly stopped after a module update with an error like something along Did not attempt to load JSON data because the request Content-Type was not 'application/json'
, maybe you are using GET
with parameters, eg for me curl "http://localhost:5000/api/mac?mac=3c:52:82:17:2e:e8"
. My code was
parser = reqparse.RequestParser()
parser.add_argument("mac", type=str)
args = parser.parse_args()
After changing it to
parser = reqparse.RequestParser()
parser.add_argument("mac", type=str ,location='args')
args = parser.parse_args()
I got the previous behaviour and could read args['mac']
after this fix.
Upvotes: 3
Reputation: 3224
You can use the Response.get_json()
method instead of the json
property, which lets you specify a force
parameter:
force
(bool) — Ignore the mimetype and always try to parse JSON
Usage would then be:
import requests
response = requests.post('http://127.0.0.1:5000/video/1', {'likes': 10})
response_data_forced_json = response.get_json(force=True)
This is actually what is called when getting the Response.json
property, only with the default arguments.
Upvotes: 1
Reputation: 2125
If you are able to change the code:
I manage to solve the issue by adding location=<target>
to parser.add_argument()
function.
parser.add_argument("email", type=str, required=True)
+ parser.add_argument("email", type=str, required=True, location='form')
You need to add the correct location of your input data. Some possible values are json
, args
, and form
. Learn more at:
https://flask-restful.readthedocs.io/en/latest/api.html#reqparse.RequestParser.parse_args
In my case, it is form
. because I use multipart/form-data
as input.
If you are unable to change the code:
Downgrade the werkzeug
to the version before this commit
Credit: Flask-restx request parser returns 400 Bad Request
Upvotes: 9
Reputation: 256
Currently following the same tutorial and faced the same issue.
Solved mine by adding the keyword argument json
for the data
response = requests.post(BASE + 'video/1', json={"likes": 10})
Upvotes: 9
Reputation: 416
You can set the header like the error message says.
import requests, json
BASE = "http://127.0.0.1:5000/"
# Set request's header.
headers = {"Content-Type": "application/json; charset=utf-8"}
# Set data.
data = {"likes": 10}
#
response = requests.post(BASE + 'video/1', headers=headers, json=data)
print("Status Code: ", response.status_code)
print("JSON Response: ", response.json())
Upvotes: 2
Reputation: 308
I don't know why you have an issue as far as I can tell you did copy him exactly how he did it. Here's a fix that'll work although I can't explain why his code works and yours doesn't. His video is two years old so it could be deprecated behaviour.
import requests
import json
BASE = "http://127.0.0.1:5000/"
payload = {"likes": 10}
headers = {'accept': 'application/json'}
response = requests.post(BASE + 'video/1', json=payload)
print(response.json())
Upvotes: 6