Ajax post to Python server: No JSON object could be decoded - python

I am getting this error from the server:
ValueError: No JSON object could be decoded
This is the ajax request from the client-side
function searchDB(profile_url) {
console.log(profile_url);
$.ajax({
type: 'POST',
url:'http://127.0.0.1:5000/update_greenhouse',
data: JSON.stringify(profile_url),
contentType: "application/json"
})
}
Server code:
#app.route('/update_greenhouse', methods=['GET', 'POST', 'OPTIONS'])
def update_gh():
y = request.data
print(y)
json.loads(y)
I am setting the contentType to be JSON. Why is the server giving me that error?

I have no idea why, but it was "OPTIONS" in the methods=[] caused the issue. Removed it and everything worked.

It seems that you're not sending proper JSON to the server. Just setting the contentType isn't enough. Your data (profile_url) needs to be encoded properly, as JSON object.
Try something like this in your request code:
data: JSON.stringify({'url': profile_url})
Your server will then get a basic dictionary back to use. If you really want to just pass a string, you can forgo the json.loads() on the server and operate direction from request.data, but for building anything more than a hello world app, I'd strongly suggest using a more structured format like JSON.
You also need to return a response (or error) for every Flask request. If you're building a JSON-based API, I'd suggest using Flask's jsonify. Something along the lines of
return flask.jsonify({'status': 'updated'})
on success, possibly with details about whatever the updated state is. If there are errors, you should return a response with the proper error code, like so:
return flask.make_response(jsonify({'error': 'Error details'}), 418)
Replacing 418 with whatever the appropriate HTTP error code may be.

Related

How do I properly format data in a Python POST request to Streamlabs API?

I'm trying to connect our application to Streamlabs' API so we can post donation alerts. To do that, I need to get an access token for the user whose channel we want to alert on. It's a normal OAuth2 thing. We hit the /authorize endpoint and get a code back, which we're then supposed to able to use to get an access token from the /token endpoint (https://dev.streamlabs.com/v1.0/reference#token-1).
But when we send the POST request for the token, we get an error saying the request is missing the "grant_type" parameter.
We're using the normal requests library. I've tried changing the format of the request to requests.post. I've tried altering the data by wrapping it in urlencode and json.dumps. Still no luck.
streamlabs_client_id = config('STREAMLABS_CLIENT_ID')
streamlabs_client_secret = config('STREAMLABS_CLIENT_SECRET')
streamlabs_redirect_uri = config('STREAMLABS_REDIRECT_URI')
grant_type = 'authorization_code'
querydict = {
"grant_type":"authorization_code",
"client_id":streamlabs_client_id,
"client_secret":streamlabs_client_secret,
"redirect_uri":streamlabs_redirect_uri,
"code":code
}
url = "https://streamlabs.com/api/v1.0/token"
streamlabs_response = requests.request("POST", url, data=querydict)
This is the json I get back every time:
{"error":"invalid_request","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"grant_type\" parameter."}
Any ideas what I'm doing wrong with the data?

Django json data in request.body but empty

I'm using an API which requires to send a callback to a url. Thus I configure my url and my view :
def get_callback(request):
...
some treatment with request.body
My view always returns that request.body contains " b'' ". However, it must contain a lot of informations, encoded in JSON.
Indeed I know that theses informations are well sent to the callback url, I tried with requestbin.in (http://requestb.in/1d4dkk01?inspect#10fl7s) and the raw body is full.
What could case the body to be empty ? Could it be the nginx configuration ? or in setting.py ?
Thanks you
I think, you should return response have kind of json data for view. Like it
import json
def get_call_back(request):
# Do something to return dictionary same as {'abc': xyz}
json_data = json.dumps(data)
return HttpResponse(json_data, content_type='application/json')

Return a pure json error in Tornado

def get(self):
self.set_status(400, '["reason"]')
self.finish()
return
When you get this response you can get response.error.message which has the message HTTP 400: ["reason"]. But what if you wanted a pure json response as an error. What would be the best way to get that?
The second argument to set_status() is the "reason" string, i.e. the "Not Found" in HTTP/1.1 404 Not Found. It's human-readable, not machine readable, and many HTTP clients simply discard it. You should only use this parameter when you are sending a status code that is not found in the standard list.
Instead, when you want to send a JSON message along with an error, call self.set_status(code), and then write your output as usual into the body:
self.set_status(400)
self.finish({"reason": reason})

Post print dictionary/json returns error to client

I am sending post request in the body of some json data, to process on server and I want the results back to client(c++ app on phone) in the form of json data and hence parse on mobile.
I have the following code inside handler:
class ServerHandler(tornado.web.RequestHandler):
def post(self):
data = tornado.escape.json_decode(self.request.body)
id = data.get('id',None)
#process data from db (take a while) and pack in result which is dictinary
result = process_data(id)# returns dictionary from db= takes time
print 'END OF HANDLER'
print json.dumps(result)
#before this code below I have tried also
#return result
#return self.write(result)
#return self.write(json.dumps(result))
#return json.dumps(result)
self.set_header('Content-Type', 'application/json')
json_ = tornado.escape.json_encode(result)
self.write(json_)
self.finish()
#return json.dumps(result)
I always get printed 'END OF HANDLER' and valid dictinary/json below on console but when I read at client mobile I always get
<html><title>405: Method Not Allowed</title><body>405: Method Not Allowed</body></html>
Does anyone have any idea what is the bug ?
(I am using CIwGameHttpRequest for sending request and it works when file is static =>name.json but now same content is giving error in post request. )
The error (HTTP 405 Method Not Allowed) means that you have made a request to a valid URL, but you are using an HTTP verb (e.g. GET, POST, PUT, DELETE) that cannot be used with that URL.
Your web service code appears to handle the POST verb, as evidenced by the post method name, and also by the fact that incoming requests appear to have a request body. You haven't shown us your C++ client code, so all I can do is to speculate that it is making a GET request. Does your C++ code call Request->setPOST();? (I haven't worked with CIwGameHttpRequest before, but Googling for it I found this page from which I took that line of code.)
I've not worked with Tornado before, but I imagine that there is some mechanism somewhere that allows you to connect a URL to a RequestHandler. Given that you have a 405 Method Not Allowed error rather than 404 Not Found, it seems that however this is done you've done it correctly. You issue a GET request to Tornado for the URL, it determines that it should call your handler, and only when it tries to use your handler it realises that it can't handle GET requests, concludes that your handler (and hence its URL) doesn't support GETs and returns a 405 error.

Python requests module: urlencoding json data

I'm working on an API wrapper. The spec I'm trying to build to has the following request in it:
curl -H "Content-type:application/json" -X POST -d data='{"name":"Partner13", "email":"example#example.com"}' http://localhost:5000/
This request produces the following response from a little test server I setup to see exatly what headers/params etc are sent as. This little script produces:
uri: http://localhost:5000/,
method: POST,
api_key: None,
content_type: application/json,
params: None,
data: data={"name":"Partner13", "email":"example#example.com"}
So that above is the result I want my python script to create when it hits the little test script.
I'm using the python requests module, which is the most beautiful HTTP lib I have ever used. So here is my python code:
uri = "http://localhost:5000/"
headers = {'content-type': 'application/json' }
params = {}
data = {"name":"Partner13", "email":"example#exmaple.com"}
params["data"] = json.dumps(data)
r = requests.post(uri, data=params, headers=headers)
So simple enough stuff. Set the headers, and create a dictionary for the POST parameters. That dictionary has one entry called "data" which is the JSON string of the data I want to send to the server. Then I call the post. However, the result my little test script gives back is:
uri: http://localhost:5000/,
method: POST,
api_key: None,
content_type: application/json,
params: None,
data: data=%7B%22name%22%3A+%22Partner13%22%2C+%22email%22%3A+%22example%40example.com%22%7D
So essentially the json data I wanted to send under the data parameter has been urlendcoded.
Does anyone know how to fix this? I have looked through the requests documentation and cannot seem to find a way to not auto urlencode the send data.
Thanks very much,
Kevin
When creating the object for the data keyword, simply assign a variable the result of json.dumps(data).
Also, because HTTP POST can accept both url parameters as well as data in the body of the request, and because the requests.post function has a keyword argument named "params", it might be better to use a different variable name for readability. The requests docs use the variable name "payload", so thats what I use.
data = {"name":"Partner13", "email":"example#exmaple.com"}
payload = json.dumps(data)
r = requests.post(uri, data=payload, headers=headers)
Requests automatically URL encodes dictionaries passed as data here. John_GG's solution works because rather than posting a dictionary containing the JSON encoded string in the 'data' field it simply passes the JSON encoded string directly: strings are not automatically encoded. I can't say I understand the reason for this behaviour in Requests but regardless, it is what it is. There is no way to toggle this behaviour off that I can find.
Best of luck with it, Kevin.

Categories