bug: error message "JSON parse error..." after REST-query to add-to-cart?format=json
SergeyMatsiupa opened this issue · comments
environment:
OS xUbuntu 18.04.4; Python 3.6.9; Django 3.0.8; django-shop 1.2.2 (installed according to instructions https://django-shop.readthedocs.io/en/latest/tutorial/intro.html)
STR:
- get cookie-values csrftoken and sessionid adding 1 product to cart in browser and parsing them from headers of corresponding http-request
- execute Python-code (adding 1 products unit to existing cart according to instruction 17.2.3.3. Add Product to Cart)
import httplib2
from urllib.parse import urlencode
h = httplib2.Http('.cache')
data = {
"quantity": 1,
"product": 15,
"product_code": "1004"
}
data = urlencode(data)
response, content = h.request('http://localhost:8000/catalog/smart-cards/sdxc-card-64gb/add-to-cart?format=json','POST',data,headers={'Content-Type':'application/json','accept':'application/json','Cookie':'csrftoken=3hoZkpJNer2kSNaDgO3nOa8r2fLNl6KiwtMJDCW5pbDN9jELORM2dDIYCnE8wwew;sessionid=2k0t3edvimyud5acdpvt71e5dda7jod7'})
print("response.status - {0}".format(response.status))
print("response.items() - {0}".format(response.items()))
print("content - {0}".format(content))
AR:
content - b'{"detail":"JSON parse error - Expecting value: line 1 column 1 (char 0)"}'
ER:
understandable error message in the response body
before sending a dict as JSON, you have to stringify it.
...
import json
...
data = {
"quantity": 1,
"product": 15,
"product_code": "1004"
}
data = json.dumps(data)
...
Thanks I done this, but anyway got the same error ("JSON parse error - Expecting value: line 1 column 1 (char 0)", response code 400).
So I made some investigation and find out that error occurs in django_shop_2_slug-UAkksQbw/lib/python3.6/site-packages/rest_framework/parsers.py file in parse
function of JSONParser
class on the return json.load(decoded_stream, parse_constant=parse_constant)
line of code. I checked beforehand that decoded_stream.read()
returned exactly that I sent in POST-query -
{"quantity": 1, "product": 15, "product_code": "1004"}
So problem as I think should be in json.load() function (when I tried to execute it there in more simple way as t = json.load(decoded_stream)
I also got error).
as far as I know, JSON data must be transferred (and will be received) as byte-stream, not string. Maybe you have to check this as well.
Well, I made some more investigations, and found out for now -
looks like the root cause of the issue is in the stream
parameter that is passed to method def parse(self, stream, media_type=None, parser_context=None):
of the JSONParser
class (declared in the django_shop_2_slug-UAkksQbw/lib/python3.6/site-packages/rest_framework/parsers.py file). This parameter stream
is belong to the WSGIRequest class, so according to the docstring of the def
method - it should have a 'bytestream nature' and be deserialized by json.load()
function well, but it doesn't. I checked it inside the parse
method via adding and executing in the first linestream.read()
function that returned correct JSON-byte-string - b'{"quantity": 1, "product": 15, "product_code": "1004"}', it's exactly that I passed to the REST-endpoint on the 'frontend-side', and also it should be well enough for json.load()
corresponding to it's documentation:
json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
Deserialize fp (a .read()-supporting text file or binary file containing a JSON document) to a Python object using this conversion table.
But executing json.load(stream)
in the beginning of the parse
method result in an error - 'json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)'
So I checked this case in separated code (and especially for my JSON en- and de-coding):
#JSON for to pass to the REST-endpoint
data = {
"quantity": 1,
"product": 15,
"product_code": "1004"
}
#stringify JSON for sending in request
import json
data = json.dumps(data)
##reproduce server-side JSON-decoding
import codecs, io
#making bytestream object; string is exactly that was passed to JSONParser.parse (checked inside of it)
my_stream = io.BytesIO(b'{"quantity": 1, "product": 15, "product_code": "1004"}')
#it's exactly that should be returned by by the JSONParser.parse and now it's executed successfully
data1 = json.load(my_stream)
@jrief I should ask you for some help and advice - what should I check next? actually, to have well-working REST in my django-shop is very important for now
well, looks as I got rid of this bug just by updating files in the django_shop_2_slug-UAkksQbw/lib/python3.6/site-packages/rest_framework/ project folder to corresponding ones from the official Django REST framework repository