Skip to content

Instantly share code, notes, and snippets.

@vytas7
Last active March 22, 2024 19:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vytas7/068ac5bd8a0fd118052d32e30be67792 to your computer and use it in GitHub Desktop.
Save vytas7/068ac5bd8a0fd118052d32e30be67792 to your computer and use it in GitHub Desktop.
Falcon error handling examples
import falcon
import falcon.routing
class FloatConverter(falcon.routing.BaseConverter):
def convert(self, value):
try:
return float(value)
except ValueError:
return None
def serialize_error(req, resp, exception):
preferred = req.client_prefers((falcon.MEDIA_JSON,))
if preferred == falcon.MEDIA_JSON:
resp.content_type = preferred
resp.data = exception.to_json()
else:
report = ['[Custom error serializer]\n']
for key, value in sorted(exception.to_dict().items()):
report.append(f'{key}: {value}\n')
resp.content_type = falcon.MEDIA_TEXT
resp.text = ''.join(report)
resp.append_header('Vary', 'Accept')
def handle_overflow(req, resp, ex, params):
if 'power' in params and params['power'] >= 1000:
# Reraise an instance of HTTPError
raise falcon.HTTPBadRequest(title='Too Damn High!')
# Render a custom error response
resp.content_type = falcon.MEDIA_TEXT
resp.text = 'That was too much to handle... Check your parameters.\n'
resp.status = falcon.HTTP_UNPROCESSABLE_ENTITY
class Division:
def on_get(self, req, resp, dividend, divisor):
# Divide by 0 to make Falcon return a generic 500 response
resp.media = dividend / divisor
class Exponentiation:
def on_get(self, req, resp, base, power):
resp.media = base ** power
app = falcon.App()
app.router_options.converters['float'] = FloatConverter
app.add_error_handler(OverflowError, handle_overflow)
app.set_error_serializer(serialize_error)
app.add_route('/division/{dividend:float}/{divisor:float}', Division())
app.add_route('/exponentiation/{base:float}^{power:float}', Exponentiation())
@vytas7
Copy link
Author

vytas7 commented Apr 6, 2021

Different ways to handle and format errors in Falcon.

Run as gunicorn error_handling:app (or similar, adapt to your WSGI server of choice).

Default handler for otherwise unhandled exceptions

$ http http://127.0.0.1:8000/division/1/0 
HTTP/1.1 500 Internal Server Error
Server: gunicorn
content-length: 38
content-type: application/json
vary: Accept

{
    "title": "500 Internal Server Error"
}

Format the error as plain text using a custom error serializer

$ http http://127.0.0.1:8000/division/1/0 Accept:text/plain
HTTP/1.1 500 Internal Server Error
Server: gunicorn
content-length: 59
content-type: text/plain; charset=utf-8
vary: Accept

[Custom error serializer]
title: 500 Internal Server Error

Render an error response in the error handler

$ http http://127.0.0.1:8000/exponentiation/20^900 
HTTP/1.1 422 Unprocessable Entity
Server: gunicorn
content-length: 54
content-type: text/plain; charset=utf-8

That was too much to handle... Check your parameters.

Raise an instance of HTTPError from the error handler

$ http http://127.0.0.1:8000/exponentiation/20^1000 
HTTP/1.1 400 Bad Request
Server: gunicorn
content-length: 27
content-type: application/json
vary: Accept

{
    "title": "Too Damn High!"
}

(http in the above snippets is the HTTPie HTTP client.)

@CaselIT
Copy link

CaselIT commented Apr 6, 2021

does this make sense to have this in the example folder?

@vytas7
Copy link
Author

vytas7 commented Apr 6, 2021

Probably it does, but it needs to be cleaned up a bit. I'll drop a link on the respective GH issue: falconry/falcon#1460.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment