draxous
draxous

Reputation: 59

Flask global exception handling

How could one handle exceptions globally with Flask? I have found ways to use the following to handle custom db interactions:

try:
    sess.add(cat2)
    sess.commit()
except sqlalchemy.exc.IntegrityError, exc:
    reason = exc.message
    if reason.endswith('is not unique'):
        print "%s already exists" % exc.params[0]
        sess.rollback()

The problem with try-except is I would have to run that on every aspect of my code. I can find better ways to do that for custom code. My question is directed more towards global catching and handling for:

apimanager.create_api(
    Model,
    collection_name="models",
    **base_writable_api_settings
)

I have found that this apimanager accepts validation_exceptions: [ValidationError] but I have found no examples of this being used.

I still would like a higher tier of handling that effects all db interactions with a simple concept of "If this error: show this, If another error: show something else" that just runs on all interactions/exceptions automatically without me including it on every apimanager (putting it in my base_writable_api_settings is fine I guess). (IntegrityError, NameError, DataError, DatabaseError, etc)

Upvotes: 3

Views: 3258

Answers (2)

Paul Becotte
Paul Becotte

Reputation: 9977

I tend to set up an error handler on the app that formats the exception into a json response. Then you can create custom exceptions like UnauthorizedException...

class Unauthorized(Exception):
    status_code = 401

@app.errorhandler(Exception)
def _(error):

    trace = traceback.format_exc()
    status_code = getattr(error, 'status_code', 400)
    response_dict = dict(getattr(error, 'payload', None) or ())
    response_dict['message'] = getattr(error, 'message', None)
    response_dict['traceback'] = trace

    response = jsonify(response_dict)
    response.status_code = status_code
    traceback.print_exc(file=sys.stdout)
    return response

You can also handle specific exceptions using this pattern...

@app.errorhandler(ValidationError)
def handle_validation_error(error):
    # Do something...

Error handlers get attached to the app, not the apimanager. You probably have something like

app = Flask()
apimanager = ApiManager(app) 
...

Put this somewhere using that app object.

Upvotes: 2

A. Vidor
A. Vidor

Reputation: 2550

My preferred approach uses decorated view-functions.

You could define a decorator like the following:

def handle_exceptions(func):
  @wraps(func)
  def wrapper(*args, **kwargs):
    try:
      return func(*args, **kwargs)
    except ValidationError:
      # do something
    except HTTPException:
      # do something else ...
    except MyCustomException:
      # do a third thing

Then you can simply decorate your view-functions, e.g.

@app.route('/')
@handle_exceptions
def index():
  # ...

I unfortunately do not know about the hooks Flask-Restless offers for passing view-functions.

Upvotes: 0

Related Questions