In short, i have a Cloud Run a Python app that checks the file format as follows:
if not(object_id.endswith('.csv') or object_id.endswith(".json")):
msg = "Wrong file format!"
logging.error(f"Bad Request. error: {msg}")
return (f"Bad Request: {msg}", 400)
else:
msg = "JSON or CSV format detected."
logging.info(f"Correct format: {msg}")
When i test this locally by triggering it with Postman using the wrong file format (on purpose), i get the expected error "Bad Request" and the app stops.
But when i test it in Cloud Run, i keep getting the error 400. It doesnt exit the function it keeps retrying. Can anyone spot what i have done wrong?
I just included this code snippet as this is where the error message comes from.
I tried changing the HTTP codes between 405 and 400 as the documentation states that the containers react differently. But nothing has worked.
Instead of returning an HTTP 5xx status code, the "Bad Request" error should return an HTTP 4xx code. By doing so, Cloud Run will be informed that the problem was not caused by the server and won't attempt to process the request again.
An updated version of the code that produces the HTTP 400 status code is here:
if not(object_id.endswith('.csv') or object_id.endswith(".json")):
msg = "Wrong file format!"
logging.error(f"Bad Request. error: {msg}")
return (f"Bad Request: {msg}", 400)
else:
msg = "JSON or CSV format detected."
logging.info(f"Correct format: {msg}")
return (f"Correct format: {msg}", 200)
An HTTP 400 response code should stop Cloud Run from retrying the request and notify the client of the issue right away.
Related
we are running the load test via this command:
locust --config=./config/entity_publish_flows.conf
But after completion of load test, we see that failed apis are not getting listed in csv although failures are getting logged in log file.
Actually there are total 11 apis, but as 3 apis are giving error, only 8 apis are getting included in csv_stats report
Locust version: 2.12.2
Please suggest if I am missing something.
I solved this, you have to write like this when doing any API call by using catch_Reponse=True and response.failure("any message"):
def get(self, endpoint, headers, name=None):
with self.client.get(endpoint, headers=headers, name=name, catch_response=True,
cookies=self.user.get_cookie()) as response:
if response.status_code == 200:
Logger.log_message('GET API Call Successful for endpoint: {}'.format(endpoint))
else:
response.failure("got wrong response")
raise RescheduleTask()
I am using python 3.8, Flask 1.1.2
While trying to handle errors can't figure out a way to return status code and break code when error is found.
When everything runs fine, program return statement is as follows
return jsonify({'status':'success', 'prediction':pred}), 200
which allow me to access status_code
response = requests.post(url_path, json=data)
print(response.status_code)
>>> 200
However when error arise before reaching end of code I've tried to handle error like this:
code....
try:
code
except KeyError:
return jsonify({'error_message':'something wrong with input'}), 10
code...
return jsonify({"status":"success!", "best_actions":final_actions}), 200
When except statement is executed it outputs ConnectionError: ('Connection aborted.', BadStatusLine('HTTP/1.0 10 UNKNOWN\r\n')) which seems to happen when python client receives empty response according to Connection aborted.', BadStatusLine("''",) on server?
changing except statement like:
expect KeyError:
return jsonify({'error_message':'something wrong with input'})
allow me to obtain response.json() however cannot get response.status_code.
returning with http status_code works:
expect KeyError:
return jsonify({'error_message':'something wrong with input'}), 1xx
above code works fine however I am trying to create custom status_codes therefore I can add detailed reason and solution in my documentation.
Any help or guide to helpful resource would be greatly appreciated, thanks!
Using Python 2.7, Django on Google App Engine. I'm trying to do some simple URL checking, including checking a JSON data payload, and return a meaningful error to the user. What I have coded is basically this:
from django.core.exceptions import SuspiciousOperation
...
def check(self, request):
json_data = json.loads(request.body)
if not json_data:
raise SuspiciousOperation('Required JSON data not found in the POST request.')
...
But, when I test this in debug mode (DEBUG = True in settings.py) by omitting the JSON data, instead of returning a HTTP 400 as I expect from SuspiciousOperation, I get an HTTP 500 that contains my error message "Required JSON data not found in the POST request." The same thing occurs if I check for a valiud URL with URLValidator(): I can correctly test for a good or bad URL with the URLValidator(), but if I try to raise a custom message on a bad URL with SuspiciousOperation I get HTTP 500 instead of 400.
How can I return a meaningful error to my caller without the server error obfuscating everything when Debug is turned back off and crashing the process in the process? Is SuspiciousOperation not supported by GAE?
There was an issue raised about this on Django's bug tracker and it looks like it was fixed in 1.6 but not backported. Indeed, SuspiciousOperation is handled by a catch-all in 1.5.11 (django/django/core/handlers/base.py line 173):
except: # Handle everything else, including SuspiciousOperation, etc.
# Get the exception info now, in case another exception is thrown later.
signals.got_request_exception.send(sender=self.__class__, request=request)
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
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})
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.