Skip to content

Allow Error Handler to Return HttpResponse #458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
JavaScriptDude opened this issue Jul 19, 2022 · 4 comments
Open

Allow Error Handler to Return HttpResponse #458

JavaScriptDude opened this issue Jul 19, 2022 · 4 comments
Labels
enhancement New feature or request

Comments

@JavaScriptDude
Copy link

I would like to have full control of the response from error handlers assigned using @api.errorhandler decorator so I can obfuscate the return of calls for some usecases.

For example:

@app.errorhandler(werkzeug.exceptions.BadRequest)
def handle_bad_request(e):
    log.error("<error_dump>", error)
    response = flask.make_response()
    response.set_data(":(")
    response.status_code = 418
    response.headers['Content-Type'] = 'text/html'
    response.headers['Server'] = 'Timex Sinclair'
    return response

However, the code assumes full control of the response assuming that a dict is returned.

The change is quite simple. In Api.py after result = handler(e):

if not result is None and  issubclass(result.__class__, BaseResponse):
    return result
@JavaScriptDude JavaScriptDude added the enhancement New feature or request label Jul 19, 2022
@JavaScriptDude
Copy link
Author

Created PR #459

@JavaScriptDude
Copy link
Author

The only way to do this is at present is by doing the following which is not ideal at all and it does not allow overriding of Content-Type.

app = Flask()
app.config['ERROR_INCLUDE_MESSAGE'] = False
# ...
@app.errorhandler(werkzeug.exceptions.BadRequest)
def handle_bad_request(e):
    log.error("<error_dump>", error)
    return (":(", 418, Headers({'Server': 'Timex Sinclair'}))

@trey-stafford
Copy link

trey-stafford commented Apr 29, 2025

I have also run into this issue recently and have been unable to render an HTML response when unexpected application errors are encountered. This is unfortunate, as there are parts of my API where I would like to be able to render a nice, human-readable error message with e.g., links embedded to help documentation. As currently designed, I am forced to return a json response when using @api.errorhandler.

@trey-stafford
Copy link

I've found a hack workaround that works for my use-case, but it feels unnecessary, confusing, and prone to breakage. It relies on catching errors at the flask-restx layer (@api.errorhandler), raising a custom error there, and then catching it with the flask error handler (@app.errorhandler) which is capable of returning the HTML response that I want.

class HackError(Exception):
    """Hack error class that is only used to work around
    https://github.com/python-restx/flask-restx/issues/458."""
    pass

@api.errorhandler  # noqa
def handle_api_exception(e):
    # pass through HackErrors as a JSON response to the flask-restx backend.
    # This does NOT end up being presented to the user. 
    # They see the response returned by `handle_hack_exception` below.
    if isinstance(e, HackError):
        return {}, 500

    # Log the original error 
    err_traceback = traceback.format_exception(e)
    err_msg = f"Unhandled exception during request: {e}"
    app.logger.exception(err_msg, extra={"exception_traceback": err_traceback})

    # Raise a `HackError`, which will be handled by `handle_hack_exception`
    # below.
    raise HackError

@app.errorhandler(HackError)  # noqa
def handle_hack_exception(e):
    """Handle any exceptions raised from the application.

    https://flask.palletsprojects.com/en/stable/errorhandling/#error-handlers
    """
    # Return an HTML response
    return Response(
        render_template(
            "generic_error.html.jinja",
        ),
        content_type="text/html",
        status=500,
    )

Although this appears to work with my production configuration, I am reluctant to put it into prod.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants