Flask/Flask_restful custom 404 error message

Viewed 2921

I have a flash/flask_result app set up as the following. How can I add a custom global 404 error message to the whole app? Should I do it with tornado, or flask?

from flask import Flask
from flask_cors import CORS
from flask_restful import Api
from flask_env import MetaFlaskEnv
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.wsgi import WSGIContainer

...

#setup api app
app = Flask(__name__)
app.config.from_object(Configuration)
API = Api(app)

# allow cross site request
CORS = CORS(app, resources={r"/api/*": {"origins": "*"}})

# system endpoints
API.add_resource(Version, '/api/version')
...

if __name__ == '__main__':
    # start server
    HTTP_SERVER = HTTPServer(WSGIContainer(app))
    HTTP_SERVER.listen(port=app.config["PORT"])
    IOLoop.instance().start()
3 Answers

If you want to return a custom 404 error page, just use decorator.

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

To log the error to file and return JSON, rather than an HTML template, flask_restful's handle_error method can be overridden by creating a new Api class:

class MyApi(Api):
    def __init__(self, *args, **kwargs):
        super(MyApi, self).__init__(*args, **kwargs)
    def handle_error(self, e):
        if isinstance(e, HTTPException):
            if e.code == 404:
                log_msg = '[Web Server] %s returned %s: %s' % (request.path, e.code, e.name)
                logger.error(log_msg) # File logging configured separately (see below).  
        return super(MyApi, self).handle_error(e)

The file logging used will depend on the environment; the software here uses Gunicorn:

import logging
logger = logging.getLogger('gunicorn.error')

For restful APIs I'd use something like the following. You don't need to render a HTML template in this case.

Furthermore I recommend to log every 404 event including the requested url to:

  • fix your routes (improves user-experiences and SEO)
  • detect hackers
import logging
from flask import request

@app.errorhandler(404)
def page_not_found(e):
    # Even though Flask logs it by default, 
    # I prefer to have a logger dedicated to 404
    logger.warning('404: {0}'.format(request.url))
    return 'Not found', 404
Related