`_
-* `Flask-specific documentation `_.
+with errors including custom exceptions and 3rd party tools.
-Error handlers
---------------
+.. _common-error-codes:
-You might want to show custom error pages to the user when an error occurs.
-This can be done by registering error handlers.
+Common Error Codes
+``````````````````
-An error handler is a normal view function that returns a response, but instead
-of being registered for a route, it is registered for an exception or HTTP
-status code that would be raised while trying to handle a request.
+The following error codes are some that are often displayed to the user,
+even if the application behaves correctly:
-Registering
-```````````
+*400 Bad Request*
+ When the server will not process the request due to something that
+ the server perceives to be a client error. Such as malformed request
+ syntax, missing query parameters, etc.
-Register handlers by decorating a function with
-:meth:`~flask.Flask.errorhandler`. Or use
-:meth:`~flask.Flask.register_error_handler` to register the function later.
-Remember to set the error code when returning the response. ::
+*403 Forbidden*
+ If you have some kind of access control on your website, you will have
+ to send a 403 code for disallowed resources. So make sure the user
+ is not lost when they try to access a forbidden resource.
- @app.errorhandler(werkzeug.exceptions.BadRequest)
- def handle_bad_request(e):
- return 'bad request!', 400
+*404 Not Found*
+ The good old "chap, you made a mistake typing that URL" message. So
+ common that even novices to the internet know that 404 means: damn,
+ the thing I was looking for is not there. It's a very good idea to
+ make sure there is actually something useful on a 404 page, at least a
+ link back to the index.
- # or, without the decorator
- app.register_error_handler(400, handle_bad_request)
+*410 Gone*
+ Did you know that there the "404 Not Found" has a brother named "410
+ Gone"? Few people actually implement that, but the idea is that
+ resources that previously existed and got deleted answer with 410
+ instead of 404. If you are not deleting documents permanently from
+ the database but just mark them as deleted, do the user a favour and
+ use the 410 code instead and display a message that what they were
+ looking for was deleted for all eternity.
-:exc:`werkzeug.exceptions.HTTPException` subclasses like
-:exc:`~werkzeug.exceptions.BadRequest` and their HTTP codes are interchangeable
-when registering handlers. (``BadRequest.code == 400``)
+*500 Internal Server Error*
+ Usually happens on programming errors or if the server is overloaded.
+ A terribly good idea is to have a nice page there, because your
+ application *will* fail sooner or later.
-Non-standard HTTP codes cannot be registered by code because they are not known
-by Werkzeug. Instead, define a subclass of
-:class:`~werkzeug.exceptions.HTTPException` with the appropriate code and
-register and raise that exception class. ::
- class InsufficientStorage(werkzeug.exceptions.HTTPException):
- code = 507
- description = 'Not enough storage space.'
- app.register_error_handler(InsufficientStorage, handle_507)
+Default Error Handling
+``````````````````````
- raise InsufficientStorage()
+When building a Flask application you *will* run into exceptions. If some part
+of your code breaks while handling a request (and you have no error handlers
+registered) an "500 Internal Server Error"
+(:exc:`~werkzeug.exceptions.InternalServerError`) will be returned by default.
+Similarly, if a request is sent to an unregistered route a "404 Not Found"
+(:exc:`~werkzeug.exceptions.NotFound`) error will occur. If a route receives an
+unallowed request method a "405 Method Not Allowed"
+(:exc:`~werkzeug.exceptions.MethodNotAllowed`) will be raised. These are all
+subclasses of :class:`~werkzeug.exceptions.HTTPException` and are provided by
+default in Flask.
-Handlers can be registered for any exception class, not just
-:exc:`~werkzeug.exceptions.HTTPException` subclasses or HTTP status
-codes. Handlers can be registered for a specific class, or for all subclasses
-of a parent class.
-
-Handling
-````````
+Flask gives you to the ability to raise any HTTP exception registered by
+werkzeug. However, as the default HTTP exceptions return simple exception
+pages, Flask also offers the opportunity to customise these HTTP exceptions via
+custom error handlers as well as to add exception handlers for builtin and
+custom exceptions.
When an exception is caught by Flask while handling a request, it is first
looked up by code. If no handler is registered for the code, it is looked up
by its class hierarchy; the most specific handler is chosen. If no handler is
registered, :class:`~werkzeug.exceptions.HTTPException` subclasses show a
generic message about their code, while other exceptions are converted to a
-generic 500 Internal Server Error.
+generic "500 Internal Server Error".
For example, if an instance of :exc:`ConnectionRefusedError` is raised,
and a handler is registered for :exc:`ConnectionError` and
-:exc:`ConnectionRefusedError`,
-the more specific :exc:`ConnectionRefusedError` handler is called with the
-exception instance to generate the response.
+:exc:`ConnectionRefusedError`, the more specific :exc:`ConnectionRefusedError`
+handler is called with the exception instance to generate the response.
Handlers registered on the blueprint take precedence over those registered
globally on the application, assuming a blueprint is handling the request that
@@ -137,6 +107,348 @@ because the 404 occurs at the routing level before the blueprint can be
determined.
+
+.. _handling-errors:
+
+Handling Errors
+```````````````
+
+Sometimes when building a Flask application, you might want to raise a
+:exc:`~werkzeug.exceptions.HTTPException` to signal to the user that
+something is wrong with the request. Fortunately, Flask comes with a handy
+:func:`~flask.abort` function that aborts a request with a HTTP error from
+werkzeug as desired.
+
+Consider the code below, we might have a user profile route, but if the user
+fails to pass a username we raise a "400 Bad Request" and if the user passes a
+username but we can't find it, we raise a "404 Not Found".
+
+.. code-block:: python
+
+ from flask import abort, render_template, request
+
+ # a username needs to be supplied in the query args
+ # a successful request would be like /profile?username=jack
+ @app.route("/profile")
+ def user_profile():
+ username = request.arg.get("username")
+ # if a username isn't supplied in the request, return a 400 bad request
+ if username is None:
+ abort(400)
+
+ user = get_user(username=username)
+ # if a user can't be found by their username, return 404 not found
+ if user is None:
+ abort(404)
+
+ return render_template("profile.html", user=user)
+
+
+
+.. _custom-error-handlers:
+
+Custom error handlers
+`````````````````````
+
+The default :exc:`~werkzeug.exceptions.HTTPException` returns a black and white
+error page with a basic description, but nothing fancy. Considering
+these errors *will* be thrown during the lifetime of your application, it is
+highly advisable to customise these exceptions to improve the user experience
+of your site. This can be done by registering error handlers.
+
+An error handler is a normal view function that returns a response, but instead
+of being registered for a route, it is registered for an exception or HTTP
+status code that would be raised while trying to handle a request.
+
+It is passed the instance of the error being handled, which is most
+likely an integer that represents a :exc:`~werkzeug.exceptions.HTTPException`
+status code. For example 500 (an "Internal Server Error") which maps to
+:exc:`~werkzeug.exceptions.InternalServerError`.
+
+It is registered with the :meth:`~flask.Flask.errorhandler`
+decorator or the :meth:`~flask.Flask.register_error_handler` to register
+the function later. A handler can be registered for a status code,
+like 404 or 500, or for an built-in exception class, like KeyError,
+or a custom exception class that inherits from Exception or its subclasses.
+
+The status code of the response will not be set to the handler's code. Make
+sure to provide the appropriate HTTP status code when returning a response from
+a handler or a 200 OK HTTP code will be sent instead.
+
+.. code-block:: python
+
+ from werkzeug.exceptions import InternalServerError
+
+ # as a decorator with an int as the exception code
+ @app.errorhandler(500)
+ def handle_internal_server_error(e):
+ # returning 500 with the text sets the error handler's code
+ # make sure to provide the appropriate HTTP status code
+ # otherwise 200 will be returned as default
+ return 'Internal Server Error!', 500
+
+ # or, as a decorator with the werkzeug exception for internal server error
+ @app.errorhandler(InternalServerError)
+ def handle_internal_server_error(e):
+ # werkzeug exceptions have a code attribute
+ return 'Internal Server Error!', e.code
+
+ # or, without the decorator
+ app.register_error_handler(500, handle_internal_server_error)
+
+ # similarly with a werkzeug exception
+ app.register_error_handler(InternalServerError, handle_internal_server_error)
+
+
+
+A handler for "500 Internal Server Error" will not be used when running in
+debug mode. Instead, the interactive debugger will be shown.
+
+If there is an error handler registered for ``InternalServerError``,
+this will be invoked. As of Flask 1.1.0, this error handler will always
+be passed an instance of ``InternalServerError``, not the original
+unhandled error. The original error is available as ``e.original_exception``.
+Until Werkzeug 1.0.0, this attribute will only exist during unhandled
+errors, use ``getattr`` to get access it for compatibility.
+
+.. code-block:: python
+
+ @app.errorhandler(InternalServerError)
+ def handle_500(e):
+ original = getattr(e, "original_exception", None)
+
+ if original is None:
+ # direct 500 error, such as abort(500)
+ return render_template("500.html"), 500
+
+ # wrapped unhandled error
+ return render_template("500_unhandled.html", e=original), 500
+
+
+
+Registering Custom Exceptions
+-----------------------------
+
+You can create your own custom exceptions by subclassing
+:exc:`werkzeug.exceptions.HTTPException`. As shown above, integer HTTP codes
+are interchangable when registering handlers. (``BadRequest.code == 400``)
+
+Non-standard HTTP codes cannot be registered by code because they are not known
+by Werkzeug. Instead, define a subclass of
+:class:`~werkzeug.exceptions.HTTPException` with the appropriate code and
+register and raise that exception class:
+
+.. code-block:: python
+
+ class InsufficientStorage(werkzeug.exceptions.HTTPException):
+ code = 507
+ description = 'Not enough storage space.'
+
+ def handle_507(e):
+ return 'Not enough storage space!', 507
+
+ app.register_error_handler(InsufficientStorage, handle_507)
+
+ # during an request
+ raise InsufficientStorage()
+
+Handlers can be registered for any exception class that inherits from Exception.
+
+
+Unhandled Exceptions
+--------------------
+
+If an exception is raised in the code while Flask is handling a request and
+there is no error handler registered for that exception, a "500 Internal Server
+Error" will be returned instead. See :meth:`flask.Flask.handle_exception` for
+information about this behavior.
+
+Custom error pages
+------------------
+
+The above examples wouldn't actually be an improvement on the default
+exception pages. We can create a custom 500.html template like this:
+
+.. sourcecode:: html+jinja
+
+ {% extends "layout.html" %}
+ {% block title %}Internal Server Error{% endblock %}
+ {% block body %}
+ Internal Server Error
+ Oops... we seem to have made a mistake, sorry!
+ Go somewhere nice instead
+ {% endblock %}
+
+It can be implemented by rendering the template on "500 Internal Server Error":
+
+.. code-block:: python
+
+ from flask import render_template
+
+ @app.errorhandler(500)
+ def internal_server_error(e):
+ # note that we set the 500 status explicitly
+ return render_template('500.html'), 500
+
+
+When using the :doc:`/patterns/appfactories`:
+
+.. code-block:: python
+
+
+ from flask import Flask, render_template
+
+ def internal_server_error(e):
+ return render_template('500.html'), 500
+
+ def create_app():
+ app = Flask(__name__)
+ app.register_error_handler(500, internal_server_error)
+ return app
+
+
+When using :doc:`/blueprints`:
+
+.. code-block:: python
+
+ from flask import Blueprint
+
+ blog = Blueprint('blog', __name__)
+
+ # as a decorator
+ @blog.errorhandler(500)
+ def internal_server_error(e):
+ return render_template('500.html'), 500
+
+ # or with register_error_handler
+ blog.register_error_handler(500, internal_server_error)
+
+
+
+In blueprints errorhandlers will simply work as expected; however, there is a caveat
+concerning handlers for 404 and 405 exceptions. These errorhandlers are only
+invoked from an appropriate ``raise`` statement or a call to ``abort`` in another
+of the blueprint's view functions; they are not invoked by, e.g., an invalid URL
+access. This is because the blueprint does not "own" a certain URL space, so
+the application instance has no way of knowing which blueprint error handler it
+should run if given an invalid URL. If you would like to execute different
+handling strategies for these errors based on URL prefixes, they may be defined
+at the application level using the ``request`` proxy object:
+
+.. code-block:: python
+
+ from flask import jsonify, render_template
+
+ # at the application level
+ # not the blueprint level
+ @app.errorhandler(404)
+ def page_not_found(e):
+ # if a request is in our blog URL space
+ if request.path.startswith('/blog/'):
+ # we return a custom blog 404 page
+ return render_template("blog/404.html"), 404
+ else:
+ # otherwise we return our generic site-wide 404 page
+ return render_template("404.html"), 404
+
+
+ @app.errorhandler(405)
+ def method_not_allowed(e):
+ # if a request has the wrong method to our API
+ if request.path.startswith('/api/'):
+ # we return a json saying so
+ return jsonify(message="Method Not Allowed"), 405
+ else:
+ # otherwise we return a generic site-wide 405 page
+ return render_template("405.html"), 405
+
+
+
+More information on error handling with blueprint can be found in
+:doc:`/blueprints`.
+
+
+Returning API errors as JSON
+````````````````````````````
+
+When building APIs in Flask, some developers realise that the builtin
+exceptions are not expressive enough for APIs and that the content type of
+:mimetype:`text/html` they are emitting is not very useful for API consumers.
+
+Using the same techniques as above and :func:`~flask.json.jsonify` we can return JSON
+responses to API errors. :func:`~flask.abort` is called
+with a ``description`` parameter. The errorhandler will
+use that as the JSON error message, and set the status code to 404.
+
+.. code-block:: python
+
+ from flask import abort, jsonify
+
+ @app.errorhandler(404)
+ def resource_not_found(e):
+ return jsonify(error=str(e)), 404
+
+ @app.route("/cheese")
+ def get_one_cheese():
+ resource = get_resource()
+
+ if resource is None:
+ abort(404, description="Resource not found")
+
+ return jsonify(resource)
+
+
+
+We can also create custom exception classes; for instance, for an API we can
+introduce a new custom 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:
+
+.. code-block:: python
+
+ from flask import jsonify, request
+
+ class InvalidAPIUsage(Exception):
+ status_code = 400
+
+ def __init__(self, message, status_code=None, payload=None):
+ super().__init__()
+ 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
+
+ @app.errorhandler(InvalidAPIUsage)
+ def invalid_api_usage(e):
+ return jsonify(e.to_dict())
+
+ # an API app route for getting user information
+ # a correct request might be /api/user?user_id=420
+ @app.route("/api/user")
+ def user_api(user_id):
+ user_id = request.arg.get("user_id")
+ if not user_id:
+ raise InvalidAPIUsage("No user id provided!")
+
+ user = get_user(user_id=user_id)
+ if not user:
+ raise InvalidAPIUsage("No such user!", status_code=404)
+
+ return jsonify(user.to_dict())
+
+
+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.
+
+
Generic Exception Handlers
``````````````````````````
@@ -169,6 +481,11 @@ so you don't lose information about the HTTP error.
response.content_type = "application/json"
return response
+ # or using jsonify
+ @app.errorhandler(HTTPException)
+ def handle_exception(e):
+ return jsonify("code": e.code, "name": e.name, "description": e.description), e.code
+
An error handler for ``Exception`` might seem useful for changing how
all errors, even unhandled ones, are presented to the user. However,
@@ -196,35 +513,42 @@ register handlers for both ``HTTPException`` and ``Exception``, the
``Exception`` handler will not handle ``HTTPException`` subclasses
because it the ``HTTPException`` handler is more specific.
-Unhandled Exceptions
-````````````````````
-When there is no error handler registered for an exception, a 500
-Internal Server Error will be returned instead. See
-:meth:`flask.Flask.handle_exception` for information about this
-behavior.
+Generic Error Pages
+-------------------
-If there is an error handler registered for ``InternalServerError``,
-this will be invoked. As of Flask 1.1.0, this error handler will always
-be passed an instance of ``InternalServerError``, not the original
-unhandled error. The original error is available as ``e.original_exception``.
-Until Werkzeug 1.0.0, this attribute will only exist during unhandled
-errors, use ``getattr`` to get access it for compatibility.
+If we pass in the exception into a template as below:
.. code-block:: python
- @app.errorhandler(InternalServerError)
- def handle_500(e):
- original = getattr(e, "original_exception", None)
+ from werkzeug.exceptions import HTTPException
- if original is None:
- # direct 500 error, such as abort(500)
- return render_template("500.html"), 500
+ @app.errorhandler(HTTPException)
+ def handle_exception(e):
+ return render_template("exception.html", e=e), e.code
- # wrapped unhandled error
- return render_template("500_unhandled.html", e=original), 500
+.. sourcecode:: html+jinja
+
+ {% extends "layout.html" %}
+ {% block title %}{{ e.name }}{% endblock %}
+ {% block body %}
+
{{ e.code }} {{ e.name }}
+ {{ e.description }}
+ Go home
+ {% endblock %}
+
+
+
+Debugging Application Errors
+````````````````````````````
+
+For production applications, configure your application with logging and
+notifications as described in :doc:`/logging`. This section provides
+pointers when debugging deployment configuration and digging deeper with a
+full-featured Python debugger.
+
Logging
-------
@@ -232,14 +556,6 @@ See :doc:`/logging` for information on how to log exceptions, such as by
emailing them to admins.
-Debugging Application Errors
-============================
-
-For production applications, configure your application with logging and
-notifications as described in :doc:`/logging`. This section provides
-pointers when debugging deployment configuration and digging deeper with a
-full-featured Python debugger.
-
When in Doubt, Run Manually
---------------------------
@@ -292,3 +608,47 @@ you could have something like::
use_debugger = app.debug and not(app.config.get('DEBUG_WITH_APTANA'))
app.run(use_debugger=use_debugger, debug=app.debug,
use_reloader=use_debugger, host='0.0.0.0')
+
+
+.. _error-logging-tools:
+
+
+Error Logging Tools
+-------------------
+
+Sending error mails, even if just for critical ones, can become
+overwhelming if enough users are hitting the error and log files are
+typically never looked at. This is why we recommend using `Sentry
+`_ for dealing with application errors. It's
+available as an Open Source project `on GitHub
+`_ and is also available as a `hosted version
+`_ which you can try for free. Sentry
+aggregates duplicate errors, captures the full stack trace and local
+variables for debugging, and sends you mails based on new errors or
+frequency thresholds.
+
+To use Sentry you need to install the `sentry-sdk` client with extra `flask` dependencies::
+
+ $ pip install sentry-sdk[flask]
+
+And then add this to your Flask app::
+
+ import sentry_sdk
+ from sentry_sdk.integrations.flask import FlaskIntegration
+
+ sentry_sdk.init('YOUR_DSN_HERE',integrations=[FlaskIntegration()])
+
+The `YOUR_DSN_HERE` value needs to be replaced with the DSN value you get
+from your Sentry installation.
+
+After installation, failures leading to an Internal Server Error
+are automatically reported to Sentry and from there you can
+receive error notifications.
+
+Follow-up reads:
+
+* Sentry also supports catching errors from your worker queue (RQ, Celery) in a
+ similar fashion. See the `Python SDK docs
+ `_ for more information.
+* `Getting started with Sentry `_
+* `Flask-specific documentation `_.
diff --git a/docs/patterns/apierrors.rst b/docs/patterns/apierrors.rst
deleted file mode 100644
index 90e8c13d..00000000
--- a/docs/patterns/apierrors.rst
+++ /dev/null
@@ -1,63 +0,0 @@
-Implementing API Exceptions
-===========================
-
-It's very common to implement RESTful APIs on top of Flask. One of the
-first things that developers run into is the realization that the builtin
-exceptions are not expressive enough for APIs and that the content type of
-:mimetype:`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 jsonify
-
- 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(InvalidUsage)
- 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/errorpages.rst b/docs/patterns/errorpages.rst
deleted file mode 100644
index cf7462af..00000000
--- a/docs/patterns/errorpages.rst
+++ /dev/null
@@ -1,123 +0,0 @@
-Custom Error Pages
-==================
-
-Flask comes with a handy :func:`~flask.abort` function that aborts a
-request with an HTTP error code early. It will also provide a plain black
-and white error page for you with a basic description, but nothing fancy.
-
-Depending on the error code it is less or more likely for the user to
-actually see such an error.
-
-Common Error Codes
-------------------
-
-The following error codes are some that are often displayed to the user,
-even if the application behaves correctly:
-
-*404 Not Found*
- The good old "chap, you made a mistake typing that URL" message. So
- common that even novices to the internet know that 404 means: damn,
- the thing I was looking for is not there. It's a very good idea to
- make sure there is actually something useful on a 404 page, at least a
- link back to the index.
-
-*403 Forbidden*
- If you have some kind of access control on your website, you will have
- to send a 403 code for disallowed resources. So make sure the user
- is not lost when they try to access a forbidden resource.
-
-*410 Gone*
- Did you know that there the "404 Not Found" has a brother named "410
- Gone"? Few people actually implement that, but the idea is that
- resources that previously existed and got deleted answer with 410
- instead of 404. If you are not deleting documents permanently from
- the database but just mark them as deleted, do the user a favour and
- use the 410 code instead and display a message that what they were
- looking for was deleted for all eternity.
-
-*500 Internal Server Error*
- Usually happens on programming errors or if the server is overloaded.
- A terribly good idea is to have a nice page there, because your
- application *will* fail sooner or later (see also:
- :doc:`/errorhandling`).
-
-
-Error Handlers
---------------
-
-An error handler is a function that returns a response when a type of error is
-raised, similar to how a view is a function that returns a response when a
-request URL is matched. It is passed the instance of the error being handled,
-which is most likely a :exc:`~werkzeug.exceptions.HTTPException`. An error
-handler for "500 Internal Server Error" will be passed uncaught exceptions in
-addition to explicit 500 errors.
-
-An error handler is registered with the :meth:`~flask.Flask.errorhandler`
-decorator or the :meth:`~flask.Flask.register_error_handler` method. A handler
-can be registered for a status code, like 404, or for an exception class.
-
-The status code of the response will not be set to the handler's code. Make
-sure to provide the appropriate HTTP status code when returning a response from
-a handler.
-
-A handler for "500 Internal Server Error" will not be used when running in
-debug mode. Instead, the interactive debugger will be shown.
-
-Here is an example implementation for a "404 Page Not Found" exception::
-
- from flask import render_template
-
- @app.errorhandler(404)
- def page_not_found(e):
- # note that we set the 404 status explicitly
- return render_template('404.html'), 404
-
-When using the :doc:`appfactories`::
-
- from flask import Flask, render_template
-
- def page_not_found(e):
- return render_template('404.html'), 404
-
- def create_app(config_filename):
- app = Flask(__name__)
- app.register_error_handler(404, page_not_found)
- return app
-
-An example template might be this:
-
-.. sourcecode:: html+jinja
-
- {% extends "layout.html" %}
- {% block title %}Page Not Found{% endblock %}
- {% block body %}
- Page Not Found
- What you were looking for is just not there.
-
go somewhere nice
- {% endblock %}
-
-
-Returning API errors as JSON
-----------------------------
-
-When using Flask for web APIs, you can use the same techniques as above
-to return JSON responses to API errors. :func:`~flask.abort` is called
-with a ``description`` parameter. The :meth:`~flask.errorhandler` will
-use that as the JSON error message, and set the status code to 404.
-
-.. code-block:: python
-
- from flask import abort, jsonify
-
- @app.errorhandler(404)
- def resource_not_found(e):
- return jsonify(error=str(e)), 404
-
- @app.route("/cheese")
- def get_one_cheese():
- resource = get_resource()
-
- if resource is None:
- abort(404, description="Resource not found")
-
- return jsonify(resource)
diff --git a/docs/patterns/index.rst b/docs/patterns/index.rst
index a9727e3d..f765cd8a 100644
--- a/docs/patterns/index.rst
+++ b/docs/patterns/index.rst
@@ -18,7 +18,6 @@ collected in the following pages.
packages
appfactories
appdispatch
- apierrors
urlprocessors
distribute
fabric
@@ -31,7 +30,6 @@ collected in the following pages.
templateinheritance
flashing
jquery
- errorpages
lazyloading
mongoengine
favicon