From f9f8180f15005eca9db4af23f0abe48c56458efc Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 9 Jun 2013 17:26:10 +0100 Subject: [PATCH] Added documentation on API error handlers --- docs/patterns/apierrors.rst | 63 +++++++++++++++++++++++++++++++++++++ docs/patterns/index.rst | 1 + 2 files changed, 64 insertions(+) create mode 100644 docs/patterns/apierrors.rst diff --git a/docs/patterns/apierrors.rst b/docs/patterns/apierrors.rst new file mode 100644 index 00000000..74abf22b --- /dev/null +++ b/docs/patterns/apierrors.rst @@ -0,0 +1,63 @@ +Implementing API Exceptions +=========================== + +It's very common to implement RESTful APIs on top of Flask. One of the +first thing that developers run into is the realization that the builtin +exceptions are not expressive enough for APIs and that the content type of +``text/html`` they are emitting is not very useful for API consumers. + +The better solution than using ``abort`` to signal errors for invalid API +usage is to implement your own exception type and install an error handler +for it that produces the errors in the format the user is expecting. + +Simple Exception Class +---------------------- + +The basic idea is to introduce a new exception that can take a proper +human readable message, a status code for the error and some optional +payload to give more context for the error. + +This is a simple example:: + + from flask import jsonfiy + + class InvalidUsage(Exception): + status_code = 400 + + def __init__(self, message, status_code=None, payload=None): + Exception.__init__(self) + self.message = message + if status_code is not None: + self.status_code = status_code + self.payload = payload + + def to_dict(self): + rv = dict(self.payload or ()) + rv['message'] = self.message + return rv + +A view can now raise that exception with an error message. Additionally +some extra payload can be provided as a dictionary through the `payload` +parameter. + +Registering an Error Handler +---------------------------- + +At that point views can raise that error, but it would immediately result +in an internal server error. The reason for this is that there is no +handler registered for this error class. That however is easy to add:: + + @app.errorhandler(InvalidAPIUsage) + def handle_invalid_usage(error): + response = jsonify(error.to_dict()) + response.status_code = error.status_code + return response + +Usage in Views +-------------- + +Here is how a view can use that functionality:: + + @app.route('/foo') + def get_foo(): + raise InvalidUsage('This view is gone', status_code=410) diff --git a/docs/patterns/index.rst b/docs/patterns/index.rst index 8a9bf1ca..a64b0bb2 100644 --- a/docs/patterns/index.rst +++ b/docs/patterns/index.rst @@ -19,6 +19,7 @@ Snippet Archives `_. packages appfactories appdispatch + apierrors urlprocessors distribute fabric