着信リクエストデータをFlaskで処理する方法
序章
Webアプリケーションでは、ユーザーからの着信要求データを処理する必要があることがよくあります。 このペイロードは、クエリ文字列、フォームデータ、JSONオブジェクトの形をとることができます。 Flask は、他のWebフレームワークと同様に、リクエストデータにアクセスできます。
このチュートリアルでは、クエリ文字列、フォームデータ、またはJSONオブジェクトのいずれかを受け入れる3つのルートを使用してFlaskアプリケーションを構築します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- このプロジェクトでは、Pythonをローカル環境にインストールする必要があります。
- このプロジェクトでは、 Pipenv を使用します。これは、Pythonの世界にすべてのパッケージングの世界の最高のものをもたらすことを目的とした、本番環境に対応したツールです。 Pipfile、pip、およびvirtualenvを1つのコマンドに利用します。
- APIエンドポイントをテストするには、Postmanなどのツールをダウンロードしてインストールする必要があります。
このチュートリアルは、Pipenv v2020.11.15、Python v3.9.0、およびFlaskv1.1.2で検証されました。
プロジェクトの設定
リクエストのさまざまな使用方法を示すには、Flaskアプリを作成する必要があります。 サンプルアプリはビュー関数とルートに簡略化された構造を使用していますが、このチュートリアルで学習した内容は、クラスベースのビュー、ブループリント、Flask-Viaなどの拡張機能などのビューを整理するあらゆる方法に適用できます。
まず、プロジェクトディレクトリを作成する必要があります。 ターミナルを開き、次のコマンドを実行します。
- mkdir flask_request_example
次に、新しいディレクトリに移動します。
- cd flask_request_example
次に、Flaskをインストールします。 ターミナルを開き、次のコマンドを実行します。
- pipenv install Flask
pipenv
コマンドは、このプロジェクトのvirtualenv、Pipfileを作成し、flask
、およびPipfile.lockをインストールします。
プロジェクトのvirtualenvをアクティブ化するには、次のコマンドを実行します。
- pipenv shell
Flaskの受信データにアクセスするには、request
オブジェクトを使用する必要があります。 request
オブジェクトは、リクエストからのすべての着信データを保持します。これには、mimetype、リファラー、IPアドレス、生データ、HTTPメソッド、ヘッダーなどが含まれます。
request
オブジェクトが保持するすべての情報は役立つ場合がありますが、この記事では、エンドポイントの呼び出し元から通常直接提供されるデータに焦点を当てます。
Flaskのリクエストオブジェクトにアクセスするには、Flaskライブラリからリクエストオブジェクトをインポートする必要があります。
from flask import request
その後、任意のビュー機能で使用できるようになります。
コードエディタを使用して、app.py
ファイルを作成します。 Flask
とrequest
オブジェクトをインポートします。 また、query-example
、form-example
、およびjson-example
のルートを確立します。
# import main Flask class and request object
from flask import Flask, request
# create the Flask app
app = Flask(__name__)
@app.route('/query-example')
def query_example():
return 'Query String Example'
@app.route('/form-example')
def form_example():
return 'Form Data Example'
@app.route('/json-example')
def json_example():
return 'JSON Object Example'
if __name__ == '__main__':
# run app in debug mode on port 5000
app.run(debug=True, port=5000)
次に、ターミナルを開き、次のコマンドでアプリを起動します。
- python app.py
アプリはポート5000で起動するため、次のリンクを使用してブラウザで各ルートを表示できます。
http://127.0.0.1:5000/query-example (or localhost:5000/query-example)
http://127.0.0.1:5000/form-example (or localhost:5000/form-example)
http://127.0.0.1:5000/json-example (or localhost:5000/json-example)
コードは3つのルートを確立し、各ルートにアクセスすると、それぞれ"Query String Example"
、"Form Data Example"
、および"JSON Object Example"
のメッセージが表示されます。
クエリ引数の使用
クエリ文字列に追加するURL引数は、データをWebアプリに渡す一般的な方法です。 Webを閲覧しているときに、以前にクエリ文字列に遭遇した可能性があります。
クエリ文字列は次のようになります。
example.com?arg1=value1&arg2=value2
クエリ文字列は、疑問符(?
)文字の後に始まります。
example.com?arg1=value1&arg2=value2
また、アンパサンド(&
)文字で区切られたキーと値のペアがあります。
example.com?arg1=value1&arg2=value2
ペアごとに、キーの後に等号(=
)文字が続き、その後に値が続きます。
arg1 : value1
arg2 : value2
クエリ文字列は、ユーザーがアクションを実行する必要のないデータを渡す場合に役立ちます。 アプリのどこかにクエリ文字列を生成してURLに追加すると、ユーザーがリクエストを行うと、データが自動的に渡されます。 クエリ文字列は、メソッドとしてGETを持つフォームによって生成することもできます。
query-example
ルートにクエリ文字列を追加しましょう。 この架空の例では、画面に表示されるプログラミング言語の名前を指定します。 "language"
のキーと"Python"
の値を作成します。
http://127.0.0.1:5000/query-example?language=Python
アプリを実行してそのURLに移動すると、"Query String Example"
のメッセージが引き続き表示されます。
クエリ引数を処理する部分をプログラムする必要があります。 このコードは、request.args.get('language')
またはrequest.args['language']
のいずれかを使用して、language
キーを読み込みます。
request.args.get('language')
を呼び出すことにより、language
キーがURLに存在しない場合でも、アプリケーションは実行を継続します。 その場合、メソッドの結果はNone
になります。
request.args['language']
を呼び出すと、language
キーがURLに存在しない場合、アプリは400エラーを返します。
クエリ文字列を処理するときは、アプリが失敗しないようにrequest.args.get()
を使用することをお勧めします。
language
キーを読んで、出力として表示してみましょう。
app.py
のquery-example
ルートを次のコードで変更します。
@app.route('/query-example')
def query_example():
# if key doesn't exist, returns None
language = request.args.get('language')
return '''<h1>The language value is: {}</h1>'''.format(language)
次に、アプリを実行して次のURLに移動します。
http://127.0.0.1:5000/query-example?language=Python
ブラウザに次のメッセージが表示されます。
OutputThe language value is: Python
URLからの引数は、language
変数に割り当てられてから、ブラウザーに返されます。
クエリ文字列パラメータをさらに追加するには、URLの末尾にアンパサンドと新しいキーと値のペアを追加できます。 "framework"
のキーと"Flask"
の値を作成します。
http://127.0.0.1:5000/query-example?language=Python&framework=Flask
さらに必要な場合は、アンパサンドとキーと値のペアを追加し続けます。 "website"
のキーと"DigitalOcean"
の値を作成します。
http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean
これらの値にアクセスするには、request.args.get()
またはrequest.args[]
のいずれかを引き続き使用します。 両方を使用して、キーが欠落している場合に何が起こるかを示しましょう。 query_example
ルートを変更して、結果の値を変数に割り当ててから、次のように表示します。
@app.route('/query-example')
def query_example():
# if key doesn't exist, returns None
language = request.args.get('language')
# if key doesn't exist, returns a 400, bad request error
framework = request.args['framework']
# if key doesn't exist, returns None
website = request.args.get('website')
return '''
<h1>The language value is: {}</h1>
<h1>The framework value is: {}</h1>
<h1>The website value is: {}'''.format(language, framework, website)
次に、アプリを実行して次のURLに移動します。
http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean
ブラウザに次のメッセージが表示されます。
OutputThe language value is: Python
The framework value is: Flask
The website value is: DigitalOcean
URLからlanguage
キーを削除します。
http://127.0.0.1:5000/query-example?framework=Flask&website=DigitalOcean
language
に値が指定されていない場合、ブラウザはNone
とともに次のメッセージを表示する必要があります。
OutputThe language value is: None
The framework value is: Flask
The website value is: DigitalOcean
URLからframework
キーを削除します。
http://127.0.0.1:5000/query-example?language=Python&website=DigitalOcean
framework
の値を想定しているため、ブラウザでエラーが発生するはずです。
Outputwerkzeug.exceptions.BadRequestKeyError
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'framework'
これで、クエリ文字列の処理について理解できました。 次のタイプの受信データに進みましょう。
フォームデータの使用
フォームデータは、POSTリクエストとしてルートに送信されたフォームから取得されます。 そのため、URLのデータを表示する代わりに(フォームがGETリクエストで送信された場合を除く)、フォームデータはバックグラウンドでアプリに渡されます。 渡されたフォームデータを簡単に確認することはできませんが、アプリはそれを読み取ることができます。
これを示すために、app.py
のform-example
ルートを変更して、GET要求とPOST要求の両方を受け入れ、フォームを返します。
# allow both GET and POST requests
@app.route('/form-example', methods=['GET', 'POST'])
def form_example():
return '''
<form method="POST">
<div><label>Language: <input type="text" name="language"></label></div>
<div><label>Framework: <input type="text" name="framework"></label></div>
<input type="submit" value="Submit">
</form>'''
次に、アプリを実行して次のURLに移動します。
http://127.0.0.1:5000/form-example
ブラウザは、language
用とframework
用の2つの入力フィールドと送信ボタンを備えたフォームを表示する必要があります。
このフォームについて知っておくべき最も重要なことは、フォームを生成したのと同じルートに対してPOSTリクエストを実行することです。 アプリで読み取られるキーはすべて、フォーム入力のname
属性から取得されます。 この場合、language
とframework
が入力の名前であるため、アプリ内の入力にアクセスできます。
ビュー関数内で、リクエストメソッドがGETかPOSTかを確認する必要があります。 GETリクエストの場合は、フォームを表示できます。 それ以外の場合、POSTリクエストの場合は、受信データを処理する必要があります。
app.py
のform-example
ルートを次のコードで変更します。
# allow both GET and POST requests
@app.route('/form-example', methods=['GET', 'POST'])
def form_example():
# handle the POST request
if request.method == 'POST':
language = request.form.get('language')
framework = request.form.get('framework')
return '''
<h1>The language value is: {}</h1>
<h1>The framework value is: {}</h1>'''.format(language, framework)
# otherwise handle the GET request
return '''
<form method="POST">
<div><label>Language: <input type="text" name="language"></label></div>
<div><label>Framework: <input type="text" name="framework"></label></div>
<input type="submit" value="Submit">
</form>'''
次に、アプリを実行して次のURLに移動します。
http://127.0.0.1:5000/form-example
language
フィールドにPython
の値を入力し、framework
フィールドにFlask
の値を入力します。 次に、送信を押します。
ブラウザに次のメッセージが表示されます。
OutputThe language value is: Python
The framework value is: Flask
これで、フォームデータの処理について理解できました。 次のタイプの受信データに進みましょう。
JSONデータの使用
JSONデータは通常、ルートを呼び出すプロセスによって構築されます。
JSONオブジェクトの例は次のようになります。
{
"language" : "Python",
"framework" : "Flask",
"website" : "Scotch",
"version_info" : {
"python" : "3.9.0",
"flask" : "1.1.2"
},
"examples" : ["query", "form", "json"],
"boolean_test" : true
}
この構造により、クエリ文字列やフォームデータとは対照的に、はるかに複雑なデータを渡すことができます。 この例では、ネストされたJSONオブジェクトとアイテムの配列が表示されます。 Flaskはこの形式のデータを処理できます。
app.py
のform-example
ルートを変更して、POST要求を受け入れ、GETなどの他の要求を無視します。
@app.route('/json-example', methods=['POST'])
def json_example():
return 'JSON Object Example'
クエリ文字列やフォームデータに使用されるWebブラウザーとは異なり、この記事では、JSONオブジェクトを送信するために、Postmanを使用してカスタムリクエストをURLに送信します。
注:リクエストのためにPostmanインターフェースをナビゲートするための支援が必要な場合は、公式ドキュメントを参照してください。
Postmanで、URLを追加し、タイプをPOSTに変更します。 本文タブで、 raw に変更し、ドロップダウンからJSONを選択します。
これらの設定は、PostmanがJSONデータを適切に送信できるようにするために必要です。これにより、FlaskアプリはJSONを受信していることを認識します。
POST http://127.0.0.1:5000/json-example
Body
raw JSON
次に、前のJSONの例をテキスト入力にコピーします。
リクエストを送信すると、応答として"JSON Object Example"
が返されます。 これはかなり反気候的ですが、JSONデータ応答を処理するためのコードがまだ記述されていないため、予想されます。
データを読み取るには、FlaskがJSONデータをPythonデータ構造に変換する方法を理解する必要があります。
- オブジェクトであるものはすべてPythondictに変換されます。 JSONの
{"key" : "value"}
は、Pythonで値を返すsomedict['key']
に対応します。 - JSONの配列は、Pythonのリストに変換されます。 構文は同じなので、リストの例を次に示します。
[1,2,3,4,5]
- JSONオブジェクトの引用符内の値は、Pythonでは文字列になります。
- ブール値の
true
およびfalse
は、PythonではTrue
およびFalse
になります。 - 最後に、引用符で囲まれていない数字は、Pythonでは数字になります。
次に、着信JSONデータを読み取るためのコードに取り組みましょう。
まず、request.get_json()
を使用して、JSONオブジェクトから変数にすべてを割り当てましょう。
request.get_json()
はJSONオブジェクトをPythonデータに変換します。 json-example
ルートに次の変更を加えて、着信要求データを変数に割り当て、それらを返します。
# GET requests will be blocked
@app.route('/json-example', methods=['POST'])
def json_example():
request_data = request.get_json()
language = request_data['language']
framework = request_data['framework']
# two keys are needed because of the nested object
python_version = request_data['version_info']['python']
# an index is needed because of the array
example = request_data['examples'][0]
boolean_test = request_data['boolean_test']
return '''
The language value is: {}
The framework value is: {}
The Python version is: {}
The item at index 0 in the example list is: {}
The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)
トップレベルにない要素にアクセスする方法に注意してください。 ['version']['python']
は、ネストされたオブジェクトを入力しているために使用されます。 また、['examples'][0]
は、examples配列の0番目のインデックスにアクセスするために使用されます。
リクエストとともに送信されたJSONオブジェクトに、view関数でアクセスされるキーがない場合、リクエストは失敗します。 キーが存在しないときに失敗したくない場合は、キーにアクセスする前に、キーが存在するかどうかを確認する必要があります。
# GET requests will be blocked
@app.route('/json-example', methods=['POST'])
def json_example():
request_data = request.get_json()
language = None
framework = None
python_version = None
example = None
boolean_test = None
if request_data:
if 'language' in request_data:
language = request_data['language']
if 'framework' in request_data:
framework = request_data['framework']
if 'version_info' in request_data:
if 'python' in request_data['version_info']:
python_version = request_data['version_info']['python']
if 'examples' in request_data:
if (type(request_data['examples']) == list) and (len(request_data['examples']) > 0):
example = request_data['examples'][0]
if 'boolean_test' in request_data:
boolean_test = request_data['boolean_test']
return '''
The language value is: {}
The framework value is: {}
The Python version is: {}
The item at index 0 in the example list is: {}
The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)
アプリを実行し、Postmanを使用してサンプルのJSONリクエストを送信します。 応答では、次の出力が得られます。
OutputThe language value is: Python
The framework value is: Flask
The Python version is: 3.9
The item at index 0 in the example list is: query
The boolean value is: false
これで、JSONオブジェクトの処理について理解できました。
結論
この記事では、クエリ文字列、フォームデータ、またはJSONオブジェクトのいずれかを受け入れる3つのルートを使用してFlaskアプリケーションを構築しました。
また、すべてのアプローチで、キーが欠落しているときに正常に失敗するという繰り返しの考慮事項に対処する必要があったことを思い出してください。
警告:この記事で取り上げられなかったトピックの1つは、ユーザー入力のサニタイズでした。 ユーザー入力をサニタイズすることで、アプリケーションによって読み取られたデータによって予期しない障害が発生したり、セキュリティ対策が回避されたりすることがなくなります。
Flaskの詳細については、Flaskトピックページで演習とプログラミングプロジェクトを確認してください。