今回もFlaskについての記事を書きました。テーマはFlaskのレスポンスについてです。Google Cloud FunctionsでFlaskが採用されているため、Flaskのレスポンスに関する知識はFlaskの中でも重要度の高い情報だと思います。他方で、柔軟な設定のために煩雑な麺が否めず、最近人気が出てきたPythonのWebアプリケーションフレームワーク”responder”に劣る部分とも言われます。今回の記事は、コード例と検証結果を交え、わかりやすくなるよう心がけました。この記事が参考になりましたら幸いです。なお、Flaskの他の記事へのリンクを下記に記載していますので、そちらも参考にして頂ければと思います。
1. はじめに(実行環境など)
今回の実行環境は以下になります。また、公式ドキュメントを参考にしていますので、不明点やさらに詳しい内容を知りたい場合はそちらを参照ください。
OS: Mac OSX Python: 3.7.3 Flask: 1.1.1 公式ドキュメントの参考ページ: http://flask.palletsprojects.com/en/1.1.x/quickstart/#about-responses
2. Flaskのレスポンス
Flaskでは、ブラウザなどのクライアントからのリクエストに対するレスポンスで、Responseオブジェクトを生成し対応します。Flaskでレスポンス処理として最も一般的なパターンはrender_template
メソッドを使ってテンプレートを読み込んだデータをview関数の戻り値として返す方法です。しかし、Flaskではこれ以外にもstr型やdict型などが戻り値として指定された場合でも対応するよう設計されています。
view関数からの戻り値の対応パターンは次の5つになります。
- Responseオブジェクトの場合
- str型データを返す場合
- dict型データを返す場合
- tuple型データを返す場合
- それ以外の場合
以下でそれぞれの対応についてコード例と一緒に説明していきます。なお、コード例については、以下のコードは共通しているものとして省略して記載しています。また実行についても適宜”FLASK_APP”の設定とflask run
で実行していますが省略しています。
from flask import Flask, render_template, make_response
app = Flask(__name__)
2-1. Responseオブジェクトを返す場合
まずはview関数の戻り値にResponseオブジェクトが指定された場合です。ResponseオブジェクトはFlaskがもつオブジェクトの1つであり、内部で利用しているWerkzeugパッケージのオブジェクトを継承したものです。このオブジェクトがview関数の戻り値に指定された場合、view関数から直接レスポンスとしてクライアント(ブラウザなど)に返されます。なお、Responseオブジェクトを生成する最も一般的な方法はmake_response
メソッドを利用する方法です。ここでもこのメソッドを利用してResponseオブジェクトを生成しています。
@app.route('/resp1')
def response_object():
resp = make_response('Response test1: Response Object')
resp_type = type(resp)
resp.headers['X-datatype'] = resp_type
return resp
ブラウザからこのURLにアクセスすると以下の画面が表示されます。
ヘッダーに格納されている”X-datatype”に記載のデータ型からResponseオブジェクトが生成され、ブラウザに返されていることがわかります。
2-2. str型データを返す場合
次は、str型データを返す場合です。view関数の戻り値でstr型データが指定された場合、そのデータとデフォルトパラメータからResponseオブジェクトが生成され、クライアントに返されます。
@app.route('/resp2')
def response_str():
res = "Response test2: String"
return res
ブラウザにアクセした時の画面は次のようになります。
2-3. dict型データを返す場合
dict型のデータがview関数の戻り値で指定された場合、Flaskのjsonify
メソッドで自動で処理が行われ、Jsonデータがブラウザに返されます。
@app.route('/resp3')
def response_dict():
res = {'Response': 'test3', 'data-type': 'dict'}
return res
これにアクセスした時の取得データを検証します。
>>> import requests >>> resq = requests.get('http://127.0.0.1:5000/resp3') >>> resq.json() {'Response': 'test3', 'data-type': 'dict'}
requestsパッケージのjsonメソッドで解析したことでJsonデータが返されたことがわかります。ブラウザでアクセスすると次のような画面になります。
2-4. tuple型データを返す場合
tuple型の場合は、レスポンスの内容だけでなく、ヘッダー、ステータスコードも指定することができます。タプルの内容は(response, status, headers)
、(response, status)
、(response, headers)
のどれかになります。status
はステータスコードを表します。またheaders
はヘッダーに付加される情報をリストまたはdict型で指定することができます。下記コード例では3つの要素全てを指定しています。
@app.route('/resp4')
def response_tuple():
resp = "Response test4: tuple"
status_code = "404"
headers = {"header1": "one", "header2": "two", "header3": "three"}
return (resp, status_code, headers)
ここにアクセスするとブラウザでは次のように表示されます。
ステータスコードが404になり、ヘッダーが3つ指定されていることがわかります。
2-5. それ以外
上記以外の場合、Flaskは戻り値を有効なWSGIアプリケーションだと推定し、その値をResponseオブジェクトに変換する試みがFlaskの内部で行われます。ただし、受け付けない値の場合、エラーが発生します。
3. 最後に
以上が、Flaskのレスポンスについてです。基本的にResponseオブジェクトへの変換を行おうとしますが、str型だけでなくタプルなども受け入れるようにできています。またdict型に対してはJsonデータに変換するようにもなっており、API設計にも配慮されています。render_template
メソッドを使うとレスポンスについて特に意識することはありませんが、アプリケーションのセキュリティ対策などでヘッダーに設定値を入れたい場合など、Flaskのレスポンスの仕組みを知っておけばすぐに対応できるようになります。短い記事ではありますが、参考になりましたら幸いです。読んで頂き、ありがとうございました。