postoronnim
postoronnim

Reputation: 556

Status code 500 not treated as exception

Making a request to the server, as in code below, I've got status code 500, which was not caught as an exception. The output was "500", but I need for all 500 codes to result in sys.exit(). Does requests.exceptions.RequestException not treat 500 as an exception or is it something else? The requests module docs http://docs.python-requests.org/en/latest/user/quickstart/#errors-and-exceptions are not very clear on what falls under this class. How do I make sure that all 500 codes result in sys.exit()?

import requests
import json
import sys

url = http://www.XXXXXXXX.com
headers = {'user':'me'}
try:
    r = requests.post(url, headers=headers)
    status = r.status_code
    response = json.dumps(r.json(), sort_keys=True, separators=(',', ': '))
    print status
except requests.exceptions.RequestException as e:
    print "- ERROR - Web service exception, msg = {}".format(e)
    if r.status_code < 500:
        print r.status_code
    else:
        sys.exit(-1)

Upvotes: 10

Views: 26163

Answers (4)

Sumant Shanbag
Sumant Shanbag

Reputation: 59

Following might help.

Generic Flask error handling functions with HTTP_RESPONSE_CODE based annotations:

listing for controller\http_error_handler.py:

from flask import make_response

def init_handle_http_errors(app):
    def prepare_error_response(error, http_error_code, invoking_handler):
        result = {}
        result["result"] = {
            "outcome": "Failure!",
            "detail": repr(error),
            "error_type": str(type(error)),
            "handler": invoking_handler
        }
        response = make_response(result, http_error_code)
        response.headers["Content-Type"] = "application/json"
        return response

#Client errors
    @app.errorhandler(400) # Bad Request
    def handle_400(error):
        return prepare_error_response(error, 400, "400")
    @app.errorhandler(404) # Not Found
    def handle_404(error):
        return prepare_error_response(error, 404, "404")
    @app.errorhandler(405) # Method Not Allowed
    def handle_405(error):
        return prepare_error_response(error, 405, "405")
    
#Server errors
    @app.errorhandler(500) # Internal Server Error
    def handle_500(error):
        return prepare_error_response(error, 500, "500")
    @app.errorhandler(501) # Not Implemented
    def handle_501(error):
        return prepare_error_response(error, 501, "501")    
    
#Generic unknown error(s)
    @app.errorhandler(Exception) # Catch all
    def handle_exception(error):
        return prepare_error_response(error, 500, "catch all")

Tester endpoint:

    @app.route("/mockhttperrors", defaults={"http_error_code": 404}, methods=["GET"])
    @app.route("/mockhttperrors/<http_error_code>", methods=["GET"])
    def mock_http_error_response(http_error_code: str):
        abort(int(http_error_code))

Results expected:

Request: https://localhost:8443/mockhttperrors/501
Response:
{
    "result": {
        "detail": "<NotImplemented '501: Not Implemented'>",
        "error_type": "<class 'werkzeug.exceptions.NotImplemented'>",
        "handler": "501",
        "outcome": "Failure!"
    }
}

Request: https://localhost:8443/mockhttperrors/404
Response:
{
    "result": {
        "detail": "<NotFound '404: Not Found'>",
        "error_type": "<class 'werkzeug.exceptions.NotFound'>",
        "handler": "404",
        "outcome": "Failure!"
    }
}

Request: https://localhost:8443/mockhttperrors/unknown-error (runtime errors)
Response:
{
    "result": {
        "detail": "ValueError(\"invalid literal for int() with base 10: 'unknown-error'\")",
        "error_type": "<class 'ValueError'>",
        "handler": "catch all",
        "outcome": "Failure!"
    }
}

This can be easily extended to accommodate for any any every type of HTTP response codes that need to be handled gracefully and return appropriate 'status code' back to the caller (client)

Upvotes: 0

jarcobi889
jarcobi889

Reputation: 835

From the Requests documentation:

If we made a bad request (a 4XX client error or 5XX server error response), we can raise it with Response.raise_for_status():

>>> bad_r = requests.get('http://httpbin.org/status/404')
>>> bad_r.status_code
404

>>> bad_r.raise_for_status()
Traceback (most recent call last):
  File "requests/models.py", line 832, in raise_for_status
    raise http_error
requests.exceptions.HTTPError: 404 Client Error

So, use

r = requests.post(url, headers=headers)
try:
    r.raise_for_status()
except requests.exceptions.HTTPError:
    # Gave a 500 or 404
else:
    # Move on with your life! Yay!

Upvotes: 9

Moses Koledoye
Moses Koledoye

Reputation: 78556

A status code 500 is not an exception. There was a server error when processing the request and the server returned a 500; more of a problem with the server than the request.

You can therefore do away with the try-except:

r = requests.post(url, headers=headers)
status = r.status_code
response = json.dumps(r.json(), sort_keys=True, separators=(',', ': '))

if str(status).startswith('5'):
    ...

Upvotes: 12

Nick T
Nick T

Reputation: 26717

If you want a successful request, but "non-OK" response to raise an error, call response.raise_for_status(). You can then catch that error and handle it appropriately. It will raise a requests.exceptions.HTTPError that has the response object hung onto the error.

Upvotes: 8

Related Questions