Flaskアプリケーションでエラーを処理する方法

著者は、Write for DOnationsプログラムの一環として、寄付を受け取るためにFree and Open Source Fundを選択しました。

はじめに

Flaskは、Python言語でWebアプリケーションを作成するための便利なツールや機能を提供する、軽量なPython Webフレームワークです。

Webアプリケーションを開発していると、アプリケーションが予想とは異なる動作をする状況に必ず遭遇します。変数のスペルミス、forループの誤用、またはif文の構築方法が原因でPythonの例外が発生することがあります。例えば、関数を宣言する前に呼び出したり、存在しないページを探したりするなどです。エラーと例外を適切に処理する方法を学ぶことで、Flaskアプリケーションの開発が容易かつスムーズになります。

このチュートリアルでは、Webアプリケーション開発時に遭遇する一般的なエラーを処理する方法を示す小さなWebアプリケーションを構築します。カスタムエラーページの作成、Flaskデバッガを使用した例外のトラブルシューティング、およびアプリケーション内のイベントの追跡にロギングを使用する方法を学びます。

前提条件

ステップ1 — Flaskデバッガの使用

このステップでは、いくつかのエラーを含むアプリケーションを作成し、デバッグモードをオフにして実行してアプリケーションの応答を確認します。その後、デバッグモードをオンにしてデバッガを使用し、アプリケーションのエラーをトラブルシューティングします。

プログラミング環境がアクティブでFlaskがインストールされている状態で、flask_appディレクトリ内にあるapp.pyファイルを編集用に開いてください:

  1. nano app.py

以下のコードをapp.pyファイル内に追加してください:

flask_app/app.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')

上記のコードでは、まずflaskパッケージからFlaskクラスをインポートします。次に、appという名前のFlaskアプリケーションインスタンスを作成します。@app.route()デコレータを使用して、index()というビュー関数を作成し、その戻り値としてrender_template()関数を呼び出します。これにより、index.htmlというテンプレートがレンダリングされます。このコードには2つのエラーがあります:1つ目はrender_template()関数をインポートしていないこと、2つ目はindex.htmlテンプレートファイルが存在しないことです。

ファイルを保存して閉じます。

次に、以下のコマンドを使用してFLASK_APP環境変数でFlaskにアプリケーションを伝えます(Windowsの場合はexportの代わりにsetを使用してください):

  1. export FLASK_APP=app

そして、flask runコマンドを使用してアプリケーションサーバーを実行します:

  1. flask run

ターミナルに以下の情報が表示されます:

Output
* Serving Flask app 'app' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

この出力は以下の情報を提供します:

  • 提供されているFlaskアプリケーション(この場合はapp.py

  • ここではproduction環境です。警告メッセージは、このサーバーが本番環境用ではないことを強調しています。このサーバーは開発用に使用しているため、この警告は無視しても構いませんが、詳細についてはFlaskドキュメントのデプロイメントオプションページを参照してください。また、Gunicornを使ったFlaskデプロイメントチュートリアルや、uWSGIを使ったチュートリアルをチェックしてみることもできます。さらに、DigitalOcean App Platformを使用してFlaskアプリケーションをデプロイするには、Gunicornを使ってApp PlatformにFlaskアプリをデプロイする方法チュートリアルに従ってください。

  • デバッグモードがオフになっています。つまり、Flaskデバッガーは実行されておらず、アプリケーションで有用なエラーメッセージが表示されません。本番環境では、詳細なエラーを表示するとアプリケーションがセキュリティ上の脆弱性に晒される可能性があります。

  • サーバーはhttp://127.0.0.1:5000/のURLで動作しています。サーバーを停止するにはCTRL+Cを使用しますが、まだそれを行わないでください。

次に、ブラウザを使ってインデックスページにアクセスしてください:

http://127.0.0.1:5000/

以下のようなメッセージが表示されます:

Output
Internal Server Error The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

これは500 Internal Server Errorで、アプリケーションコード内でサーバーが内部エラーに遭遇したことを示すサーバーエラー応答です。

ターミナルには以下の出力が表示されます:

Output
[2021-09-12 15:16:56,441] ERROR in app: Exception on / [GET] Traceback (most recent call last): File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 2070, in wsgi_app response = self.full_dispatch_request() File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1515, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1513, in full_dispatch_request rv = self.dispatch_request() File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1499, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args) File "/home/abd/python/flask/series03/flask_app/app.py", line 8, in index return render_template('index.html') NameError: name 'render_template' is not defined 127.0.0.1 - - [12/Sep/2021 15:16:56] "GET / HTTP/1.1" 500 -

上記のトレースバックは、内部サーバーエラーを引き起こしたコードを通過します。NameError: name 'render_template' is not definedという行は、問題の根本原因を示しています:render_template()関数がインポートされていません。

ここで見られるように、エラーのトラブルシューティングを行うためにターミナルに移動する必要があり、不便です。

開発サーバーでデバッグモードを有効にすることで、より良いトラブルシューティング体験を得ることができます。そのためには、CTRL+Cでサーバーを停止し、環境変数FLASK_ENVdevelopmentに設定して、以下のコマンドを使用して開発モードでアプリケーションを実行します(Windowsではexportの代わりにsetを使用します):

  1. export FLASK_ENV=development

開発サーバーを実行します:

  1. flask run

ターミナルには以下のような出力が表示されます:

Output
* Serving Flask app 'app' (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 120-484-907

ここで、環境がdevelopmentに設定され、デバッグモードがオンになっており、デバッガがアクティブであることがわかります。Debugger PINは、ブラウザのコンソールのロックを解除するために必要なPINです(以下の画像で囲まれた小さなターミナルアイコンをクリックすることでアクセスできるインタラクティブなPythonシェルです)。

ブラウザでインデックスページを更新すると、以下のページが表示されます:

ここでは、より理解しやすい形でエラーメッセージが表示されています。最初の見出しは、問題を引き起こしたPythonの例外の名前を示しています(この場合はNameError)。2行目は、直接の原因(render_template()が定義されていない、つまりこの場合はインポートされていない)を示しています。その後、実行されたFlaskの内部コードを通るトレースバックが表示されます。トレースバックは下から上に読むことが一般的で、トレースバックの最後の行には通常、最も有用な情報が含まれています。

注意:
囲まれたターミナルアイコンを使うと、ブラウザ上で異なるフレームでPythonコードを実行できます。これは、Pythonのインタラクティブシェルで行うように変数の値を確認したい場合に便利です。ターミナルアイコンをクリックすると、サーバーを実行した際に取得したDebugger PINコードを入力する必要があります。このチュートリアルでは、このインタラクティブシェルは必要ありません。

このNameErrorの問題を解決するために、サーバーを稼働させたまま、新しいターミナルウィンドウを開き、環境をアクティブにし、app.pyファイルを開いてください:

  1. nano app.py

ファイルを以下のように修正します:

flask_app/app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')

保存してファイルを閉じます。

ここで、不足していたrender_template()関数をインポートしました。

開発サーバーを稼働させた状態で、ブラウザのインデックスページを更新します。

今回は、次のような情報を含むエラーページが表示されます:

Output
jinja2.exceptions.TemplateNotFound jinja2.exceptions.TemplateNotFound: index.html

このエラーメッセージは、index.htmlテンプレートが存在しないことを示しています。

これを修正するために、コードの重複を避けるために他のテンプレートが継承するbase.htmlテンプレートファイルを作成し、それを拡張するindex.htmlテンプレートを作成します。

Flaskがテンプレートファイルを探すディレクトリであるtemplatesディレクトリを作成します。そして、お好みのエディタでbase.htmlファイルを開きます:

  1. mkdir templates
  2. nano templates/base.html

以下のコードをbase.htmlファイルに追加します:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

保存してファイルを閉じます。

この基本テンプレートには、他のテンプレートで再利用するために必要なすべてのHTMLの定型文が含まれています。titleブロックは各ページのタイトルを設定するために置き換えられ、contentブロックは各ページの内容で置き換えられます。ナビゲーションバーには2つのリンクがあり、url_for()ヘルパー関数を使用してindex()ビュー関数にリンクするインデックスページ用のリンクと、アプリケーションに含める場合のAboutページ用のリンクがあります。

次に、ベーステンプレートから継承するindex.htmlというテンプレートファイルを開きます。

  1. nano templates/index.html

以下のコードを追加してください:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Index {% endblock %}</h1>
    <h2>Welcome to FlaskApp!</h2>
{% endblock %}

ファイルを保存して閉じます。

上記のコードでは、ベーステンプレートを拡張し、contentブロックを上書きします。そして、ページタイトルを設定し、titleブロックを使用してH1ヘッダーに表示し、挨拶文をH2ヘッダーに表示します。

開発サーバーを実行している状態で、ブラウザのインデックスページを更新します。

アプリケーションにエラーが表示されなくなり、インデックスページが期待通りに表示されることがわかります。

これでデバッグモードを使用し、エラーメッセージの処理方法を学びました。次に、任意のエラーメッセージでリクエストを中断し、カスタムエラーページで応答する方法を学びます。

ステップ2 — カスタムエラーページの作成

このステップでは、ユーザーがサーバー上に存在しないデータを要求した場合に404 HTTPエラーメッセージでリクエストを中断する方法を学びます。また、404 Not Foundエラーや500 Internal Server Errorエラーなど、一般的なHTTPエラーのためのカスタムエラーページを作成する方法も学びます。

リクエストを中断し、カスタムの404 HTTPエラーページで応答する方法を示すために、いくつかのメッセージを表示するページを作成します。リクエストされたメッセージが存在しない場合、404エラーで応答します。

まず、app.pyファイルを開いて、メッセージページの新しいルートを追加します:

  1. nano app.py

ファイルの最後に以下のルートを追加します:

flask_app/app.py
# ...

@app.route('/messages/<int:idx>')
def message(idx):
    messages = ['Message Zero', 'Message One', 'Message Two']
    return render_template('message.html', message=messages[idx])

ファイルを保存して閉じます。

上記のルートでは、URL変数idxがあります。これは、表示されるメッセージを決定するインデックスです。例えば、URLが/messages/0の場合、最初のメッセージ(Message Zero)が表示されます。intコンバータを使用して、正の整数のみを受け入れます。これは、URL変数がデフォルトで文字列値を持つためです。

message()ビュー関数内には、3つのメッセージを含むmessagesという通常のPythonリストがあります。(実際のシナリオでは、これらのメッセージはデータベース、API、または他の外部データソースから取得されます。)この関数は、render_template()関数の呼び出しを返します。これには2つの引数があり、テンプレートファイルとしてmessage.htmlと、テンプレートに渡されるmessage変数があります。この変数は、URL内のidx変数の値に応じて、messagesリストからのリストアイテムを持ちます。

次に、新しいmessage.htmlテンプレートファイルを開きます:

  1. nano templates/message.html

それに次のコードを追加します:

flask_app/templates/message.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Messages {% endblock %}</h1>
    <h2>{{ message }}</h2>
{% endblock %}

ファイルを保存して閉じます。

上記のコードでは、基本テンプレートを拡張し、contentブロックを上書きしています。H1見出しにタイトル(Messages)を追加し、H2見出しでmessage変数の値を表示しています。

開発サーバーを実行している状態で、ブラウザで以下のURLにアクセスしてください:

http://127.0.0.1:5000/messages/0
http://127.0.0.1:5000/messages/1
http://127.0.0.1:5000/messages/2
http://127.0.0.1:5000/messages/3

最初の3つのURLのそれぞれで、H2にはMessage ZeroMessage One、またはMessage Twoというテキストが表示されます。しかし、4番目のURLでは、サーバーはIndexError: list index out of rangeというエラーメッセージで応答します。本番環境では、応答は500 Internal Server Errorになりますが、適切な応答は3というインデックスのメッセージが見つからないことを示す404 Not Foundです。

Flaskのabort()ヘルパー関数を使って404エラーで応答することができます。そのために、app.pyファイルを開いてください:

  1. nano app.py

最初の行を編集してabort()関数をインポートします。次に、message()ビュー関数を編集し、以下の強調表示された部分に示すようにtry ... exceptを追加します:

flask_app/app.py
from flask import Flask, render_template, abort

# ...
# ...


@app.route('/messages/<int:idx>')
def message(idx):
    messages = ['Message Zero', 'Message One', 'Message Two']
    try:
        return render_template('message.html', message=messages[idx])
    except IndexError:
        abort(404)

ファイルを保存して閉じます。

上記のコードでは、abort()関数をインポートし、リクエストを中止してエラーを返すために使用します。message()ビュー関数では、try ... except句を使って関数をラップします。まず、URLのインデックスに対応するメッセージでmessagesテンプレートを返そうとします。インデックスに対応するメッセージがない場合、IndexError例外が発生します。次に、except句を使ってそのエラーをキャッチし、abort(404)を使ってリクエストを中止し、404 Not Found HTTPエラーを返します。

開発サーバーを実行した状態で、以前にIndexErrorが発生したURL(またはインデックスが2より大きい任意のURL)にブラウザで再訪問します。

http://127.0.0.1:5000/messages/3

次のレスポンスが表示されます:

Not Found

The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.

サーバーがリクエストされたメッセージを見つけられなかったことを示す、より良いエラーメッセージが表示されるようになりました。

次に、404エラーページと500エラーページのテンプレートを作成します。

まず、特別な@app.errorhandler()デコレータを使用して、404エラーのハンドラとして関数を登録します。app.pyファイルを編集用に開きます:

nano app.py

以下のようにハイライトされた部分を追加してファイルを編集します:

flask_app/app.py
from flask import Flask, render_template, abort

app = Flask(__name__)


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


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/messages/<int:idx>')
def message(idx):
    messages = ['Message Zero', 'Message One', 'Message Two']
    try:
        return render_template('message.html', message=messages[idx])
    except IndexError:
        abort(404)

ファイルを保存して閉じます。

ここでは、@app.errorhandler()デコレータを使用して、関数page_not_found()をカスタムエラーハンドラとして登録します。この関数はエラーを引数として受け取り、テンプレート404.htmlを指定したrender_template()関数の呼び出しを返します。このテンプレートは後で作成し、必要に応じて別の名前を使用することもできます。また、render_template()呼び出しの後に整数404を返します。これにより、レスポンスのステータスコードが404であることをFlaskに伝えます。これを追加しない場合、デフォルトのステータスコードレスポンスは200となり、リクエストが成功したことを意味します。

次に、新しい404.htmlテンプレートを開きます:

  1. nano templates/404.html

以下のコードを追加します:

flask_app/templates/404.html
{% extends 'base.html' %}

{% block content %}
        <h1>{% block title %} 404 Not Found. {% endblock %}</h1>
        <p>OOPS! Sammy couldn't find your page; looks like it doesn't exist.</p>
        <p>If you entered the URL manually, please check your spelling and try again.</p>
{% endblock %}

ファイルを保存して閉じます。

他のテンプレートと同様に、基本テンプレートを拡張し、contenttitleブロックの内容を置き換え、独自のHTMLコードを追加します。ここでは、タイトルとして<h1>見出し、ページが見つからなかったことをユーザーに伝えるカスタムエラーメッセージを含む<p>タグ、およびURLを手動で入力した可能性のあるユーザー向けのヘルプメッセージがあります。

他のテンプレートと同じように、エラーページで好きなHTML、CSS、JavaScriptを使用できます。

開発サーバーを実行している状態で、ブラウザを使用して次のURLに再訪します:

http://127.0.0.1:5000/messages/3

ページには、基本テンプレートのナビゲーションバーとカスタムエラーメッセージが表示されるようになります。

同様に、500 Internal Server Errorエラーに対してカスタムエラーページを追加することもできます。app.pyファイルを開きます:

  1. nano app.py

以下のエラーハンドラを404エラーハンドラの下に追加します:

flask_app/app.py
# ...

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


@app.errorhandler(500)
def internal_error(error):
    return render_template('500.html'), 500

# ...

ここでは、404エラーハンドラと同じパターンを使用します。app.errorhandler()デコレータに500引数を指定し、internal_error()関数をエラーハンドラにします。500.htmlテンプレートをレンダリングし、ステータスコード500で応答します。

次に、カスタムエラーがどのように表示されるかをデモンストレーションするために、ファイルの最後に500 HTTPエラーで応答するルートを追加します。このルートは、デバッガが実行されているかどうかに関係なく、常に500 Internal Server Errorを返します:

flask_app/app.py

# ...
@app.route('/500')
def error500():
    abort(500)

ここでは、/500ルートを作成し、abort()関数を使用して500 HTTPエラーで応答します。

ファイルを保存して閉じます。

次に、新しい500.htmlテンプレートを開きます:

  1. nano templates/500.html

以下のコードを追加します:

flask_app/templates/500.html
{% extends 'base.html' %}

{% block content %}
        <h1>{% block title %} 500 Internal Server Error {% endblock %}</h1>
        <p>OOOOPS! Something went wrong on the server.</p>
        <p>Sammy is currently working on this issue. Please try again later.</p>
{% endblock %}

ファイルを保存して閉じます。

ここでは、404.htmlテンプレートと同じことを行います。ベーステンプレートを拡張し、コンテンツブロックをタイトルと2つのカスタムメッセージで置き換えて、内部サーバーエラーについてユーザーに通知します。

開発サーバーが稼働している状態で、500エラーを返すルートにアクセスします。

http://127.0.0.1:5000/500

カスタムページが、一般的なエラーページの代わりに表示されます。

これで、FlaskアプリケーションでHTTPエラーに対してカスタムエラーページを使用する方法を理解しました。次に、アプリケーション内のイベントを追跡するためにロギングを使用する方法を学びます。イベントの追跡は、コードの動作を理解するのに役立ち、開発やトラブルシューティングにつながります。

ステップ3 — アプリケーション内のイベントを追跡するためのロギングの使用

このステップでは、サーバーが稼働しているときやアプリケーションが使用されているときに発生するイベントを追跡するためにロギングを使用し、アプリケーションコード内で何が起こっているかを確認して、エラーのトラブルシューティングを容易にします。

開発サーバーが稼働しているときにログを見たことがあるでしょうが、通常は次のようになります:

127.0.0.1 - - [21/Sep/2021 14:36:45] "GET /messages/1 HTTP/1.1" 200 -
127.0.0.1 - - [21/Sep/2021 14:36:52] "GET /messages/2 HTTP/1.1" 200 -
127.0.0.1 - - [21/Sep/2021 14:36:54] "GET /messages/3 HTTP/1.1" 404 -

これらのログでは、以下の情報を確認できます:

  • 127.0.0.1:サーバーが稼働していたホスト。
  • [21/Sep/2021 14:36:45]:リクエストの日付と時刻。
  • GETHTTPリクエストメソッド。この場合、データを取得するためにGETが使用されています。
  • /messages/2: ユーザーがリクエストしたパス。
  • HTTP/1.1: HTTPのバージョン。
  • 200 または 404: レスポンスのステータスコード。

これらのログは、アプリケーションで発生する問題を診断するのに役立ちます。app.logger が提供するロガーを使用して、特定のリクエストに関する詳細情報を知りたい場合により多くの情報をログに記録できます。

ロギングを使用すると、異なるロギングレベルで情報を報告するためにさまざまな関数を使用できます。各レベルは、特定の重大度で発生したイベントを示します。以下の関数を使用できます:

  • app.logger.debug(): イベントに関する詳細情報。
  • app.logger.info(): 予想通りに動作していることの確認。
  • app.logger.warning(): 予期しない事象(例:「ディスク容量不足」)が発生したことの表示だが、アプリケーションは予想通りに動作しています。
  • app.logger.error(): アプリケーションの一部でエラーが発生しました。
  • app.logger.critical(): 重大なエラーが発生し、アプリケーション全体が動作を停止する可能性があります。

Flaskロガーの使用方法を示すために、app.pyファイルを開いて編集し、いくつかのイベントをログに記録します:

  1. nano app.py

message()ビュー関数を次のように編集します:

flask_app/app.py

# ...

@app.route('/messages/<int:idx>')
def message(idx):
    app.logger.info('Building the messages list...')
    messages = ['Message Zero', 'Message One', 'Message Two']
    try:
        app.logger.debug('Get message with index: {}'.format(idx))
        return render_template('message.html', message=messages[idx])
    except IndexError:
        app.logger.error('Index {} is causing an IndexError'.format(idx))
        abort(404)

# ...

ファイルを保存して閉じます。

ここでは、異なるレベルでいくつかのイベントをログに記録しました。期待通りに動作しているイベント(INFOレベル)をログに記録するためにapp.logger.info()を使用します。詳細な情報(DEBUGレベル)を記録するためにapp.logger.debug()を使用し、特定のインデックスでメッセージを取得していることを示します。そして、IndexError例外が発生したことを、問題を引き起こした特定のインデックスとともにログに記録するためにapp.logger.error()を使用します(エラーが発生したため、ERRORレベル)。

以下のURLにアクセスしてください:

http://127.0.0.1:5000/messages/1

サーバーが実行されているターミナルには、以下の情報が表示されます:

Output
[2021-09-21 15:17:02,625] INFO in app: Building the messages list... [2021-09-21 15:17:02,626] DEBUG in app: Get message with index: 1 127.0.0.1 - - [21/Sep/2021 15:17:02] "GET /messages/1 HTTP/1.1" 200 -

ここでは、app.logger.info()がログに記録するINFOメッセージと、app.logger.debug()を使用して記録したインデックス番号付きのDEBUGメッセージが表示されます。

次に、存在しないメッセージのURLにアクセスしてください:

http://127.0.0.1:5000/messages/3

ターミナルには以下の情報が表示されます:

Output
[2021-09-21 15:33:43,899] INFO in app: Building the messages list... [2021-09-21 15:33:43,899] DEBUG in app: Get message with index: 3 [2021-09-21 15:33:43,900] ERROR in app: Index 3 is causing an IndexError 127.0.0.1 - - [21/Sep/2021 15:33:43] "GET /messages/3 HTTP/1.1" 404 -

ご覧の通り、以前に見たINFODEBUGのログに加えて、インデックス3のメッセージが存在しないため、新しいERRORログがあります。

イベント、詳細情報、エラーをログに記録することで、何が問題になったかを特定し、トラブルシューティングを容易にすることができます。

このステップでは、Flaskのロガーの使い方を学びました。ロギングについてより深く理解するために、Python 3でのロギングの使い方をチェックしてください。ロギングについて詳しく知りたい場合は、FlaskのロギングドキュメントPythonのロギングに関するドキュメントを参照してください。

結論

これで、Flaskでデバッグモードを使用する方法、およびFlaskウェブアプリケーションを開発する際に遭遇する可能性のある一般的なエラーをトラブルシューティングして修正する方法を知りました。また、一般的なHTTPエラーに対するカスタムエラーページを作成し、Flaskのロガーを使用してアプリケーション内のイベントを追跡し、アプリケーションの動作を検査し理解するのに役立てました。

Flaskについてもっと読みたい場合は、Flaskのトピックページをチェックしてください。

Source:
https://www.digitalocean.com/community/tutorials/how-to-handle-errors-in-a-flask-application