Lesson 2
Custom Error Handling in Flask
Custom Error Handling in Flask

In our journey of building and enhancing our Flask application, it's important to handle errors gracefully. This is crucial not only for debugging during development but also for ensuring a smooth user experience when something goes wrong. Just as we discussed middleware that intercepts requests to handle specific tasks, a systematic approach to managing errors involves crafting custom solutions.

In this lesson, we will explore how to implement a custom error handler in Flask that manages uncaught exceptions graciously and enhances the user experience with a friendly error page.

Designing a Custom Error Page

Before diving into the logic for error handling, let's design a custom error page that will communicate any issues to users. We'll be creating this file in the app/templates directory.

HTML, XML
1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Error</title> 7</head> 8<body> 9 <!-- Display the error code in a header --> 10 <h1>Error {{code}}</h1> 11 <!-- Display the description of the error --> 12 <p>{{description}}</p> 13</body> 14</html>

This HTML template provides a simple structure to display error details. The <h1> tag shows the error code, and the <p> tag describes what went wrong.

Flask’s Error Handling Basics

Flask provides a default error page that shows technical details useful for developers, but not for users. To offer a better user experience, we can create custom error pages using the @app.errorhandler decorator, allowing more intuitive error messages.

Let's clarify how errors are handled with an example:

  1. HTTP Request: A user sends a request to the server.
  2. Error?: As the request is processed, Flask checks if an error arises.
  3. Complete Request Processing: If there’s no error, the request continues as expected.
  4. Activate Error Handler: If an error occurs, the custom error handler is activated.
  5. Show Custom Error Page: Finally, the error handler displays a friendly error page to the user.
Implementing the Error Handler Middleware

To set up middleware that handles exceptions gracefully, we'll be creating a new module in the app/middlewares directory named error_handler.py.

Python
1from flask import render_template 2from werkzeug.exceptions import HTTPException 3 4def setup_error_handler(app): 5 @app.errorhandler(Exception) 6 def handle_exception(e): 7 # Determine the error code; default to 500 if not an HTTPException 8 code = e.code if isinstance(e, HTTPException) else 500 9 # Render the custom error page with the error code and description 10 return render_template("error_page.html", code=code, description=str(e)), code

The function takes the app instance and decorates it with @app.errorhandler(Exception) to globally handle exceptions through the handle_exception function.

  • Determine Error Code:

    • If the exception is an instance of HTTPException, use e.code as the error code.
    • If it's not an HTTPException, default to a 500 error code, which stands for "Internal Server Error", indicating an unexpected condition that prevented the server from fulfilling the request.
  • Render Custom Error Page:

    • Uses Flask's render_template method to render error_page.html.
    • The rendered page displays the error code and its description.
    • Returns the HTML content along with the status code to ensure that the client is informed of the specific error encountered.

This setup allows the application to intercept exceptions and present a user-friendly error page.

Setting Up the Error Handler

Once we have our custom error handler middleware ready, the next step is to integrate it into our Flask application.

Here's how we set up the error_handler middleware in our app.py file:

Python
1from flask import Flask 2from controllers.todo_controller import todo_controller 3from middlewares.error_handler import setup_error_handler 4from models import db 5from config import Config 6 7app = Flask(__name__) 8 9app.config.from_object(Config) 10 11db.init_app(app) 12 13with app.app_context(): 14 db.create_all() 15 16# Setup error handler middleware 17setup_error_handler(app) 18 19app.register_blueprint(todo_controller) 20 21if __name__ == '__main__': 22 app.run(host='0.0.0.0', port=3000, debug=True)

This ensures that errors are efficiently managed and provide the necessary feedback to users through our custom error pages.

Testing the Custom Error Handler

To ensure that our error handler performs as expected, we can introduce a deliberate error in one of our routes inside the controllers/todo_controller.py file.

Python
1@todo_controller.route('/add', methods=['POST']) 2def add(): 3 raise Exception("This is a test error") # Raising an intentional exception 4 title = request.form.get('title') 5 description = request.form.get('description') 6 if title and description: 7 todo_service.add(title, description) 8 return redirect(url_for('todo.list_todos'))

When a client sends a POST request to the /add endpoint, this deliberate exception is raised, activating the handle_exception middleware function that processes the error and uses the error_page.html template for rendering. The HTML page will display "Error 500" as the title, and the description will read "This is a test error", which matches the string provided in the raised exception.

Summary and Next Steps

With these tools, you now know how to implement custom error handling in a Flask web application. We've set up middleware to manage exceptions and display user-friendly error pages. This capability allows your applications to handle unforeseen issues gracefully, significantly improving the user experience.

Next, you'll have the chance to apply these concepts in a controlled environment, learning how to further harness Flask's robust features.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.