8

Is there a way in Falcon framework to respond with HTTP 500 status on any unspecific exception that is not handled in resource handler? I've tried to add following handler for Exception:

api.add_error_handler(Exception, 
                      handler=lambda e, 
                      *_: exec('raise falcon.HTTPInternalServerError("Internal Server Error", "Some error")'))

But this makes impossible to throw, for example, falcon.HTTPNotFound — it is handled by the handler above and I receive 500 instead of 404.

Jav_Rock
  • 22,059
  • 20
  • 123
  • 164
Anton Patiev
  • 83
  • 1
  • 5

3 Answers3

8

Yes, it is possible. You need to define a generic error handler, check if the exception is instance of any falcon error, and if it is not, then raise your HTTP_500.

This example shows a way of doing it.

def generic_error_handler(ex, req, resp, params):
    if not isinstance(ex, HTTPError):
        raise HTTPInternalServerError("Internal Server Error", "Some error")
    else:  # reraise :ex otherwise it will gobble actual HTTPError returned from the application code ref. https://stackoverflow.com/a/60606760/248616
        raise ex

app = falcon.API()
app.add_error_handler(Exception, generic_error_handler)
Nam G VU
  • 33,193
  • 69
  • 233
  • 372
Jav_Rock
  • 22,059
  • 20
  • 123
  • 164
  • 1
    and remember that any other, more specific error handler must be registered _after_ `generic_error_handler`, which will otherwise gobble it up (see [here](https://falcon.readthedocs.io/en/stable/api/api.html#falcon.API.add_error_handler)) – charlie80 Oct 18 '18 at 11:58
  • This, however, suppresses Exceptions being raised into the Console. Is there a way to raise both internally, and respond with any (i.e. generic Exception) as falcon request-response? – Oleg Nalivajev Jan 14 '20 at 13:27
  • You can log exception `ex` before raising `HTTPInternalError` here. For example, using this method: https://docs.python.org/3/library/logging.html#logging.exception – Oleg Mar 09 '20 at 18:27
2

Accepted answer seems to gobble actual HTTPError returned from the application code. This is what worked for me:

def generic_error_handler(ex, req, resp, params):
    if not isinstance(ex, HTTPError):
        logger.exception("Internal server error")
        raise HTTPInternalServerError("Internal Server Error")
    else:
        raise ex

Oleg
  • 961
  • 8
  • 16
1

I am not sure whether I understand your question properly or not.

But you can use following approach to return respond with HTTP 500 status on any unspecific exception:

class MyFirstAPI:
    def on_post(self, req, res):
        try:
            json_data = json.loads(req.stream.read().decode('utf8'))
            # some task
            res.status = falcon.HTTP_200
            res.body = json.dumps({'status': 1, 'message': "success"})

        except Exception as e:
            res.status = falcon.HTTP_500
            res.body = json.dumps({'status': 0,
                               'message': 'Something went wrong, Please try again'
                               })
app = falcon.API()
app.add_route("/my-api/", MyFirstAPI())

Or you can also use Decorators in python as follow:

def my_500_error_decorator(func):
    def wrapper(*args):
        try:
            func(*args)
        except Exception as e:
            resp.status = falcon.HTTP_500
            resp.body = json.dumps({'status': 0, 'message': 'Server Error'})

return wrapper

class MyFirstAPI:
    @my_500_error_decorator
    def on_post(self, req, res):
        try:
            json_data = json.loads(req.stream.read().decode('utf8'))
            # some task
            res.status = falcon.HTTP_200
            res.body = json.dumps({'status': 1, 'message': "success"})
app = falcon.API()
app.add_route("/my-api/", MyFirstAPI())
Harshad Kavathiya
  • 8,939
  • 1
  • 10
  • 19