FlaskでHTTP POSTボディを取得しパースする方法 – JSONとフォームデータ

Flask は Python で Web 開発をするための素晴らしいマイクロフレームワークで、非常にミニマルなものにすることができます。

数行のコードで、数秒でREST APIを提供することができます。

from flask import Flask, request
app = Flask(__name__)


@app.route('/')
def hello():
    return 'Hello!'


if __name__ == "__main__":
    app.run()


現代のWebのバックボーンは、リクエストを送信し、レスポンスを返すHTTPプロトコルです。

これらのリクエストの背後にある意図を区別するために、いくつかの “動詞 “が実行中のタスクに関連付けられました。

GET動詞はリソースを取得したいリクエストの注釈に、POST動詞はペイロード(ボディ)を指定してリソースの作成をリクエストするために、DELETE` 動詞はリソースの削除をリクエストするために使用されます、などです。

サーバー上にリソースを作成したい場合 – サーバーに投稿するデータを含むボディを持つ POST リクエストを送信することになります。

となります。

このガイドでは、FlaskでHTTP POST Bodyを取得する方法について説明します。

一般的には、JSON データを REST API に投稿してそのデータを消費させたり、フォームデータを投稿したりすることが多いでしょう – ユーザーが Web フォームに入力し、そのデータを他の API に送信して処理します。

フォームデータを送信する場合、通常は multipart/form-data としてエンコードされ、JSON データを送信する場合は、通常は application/json としてエンコードされます。

この情報はPOSTリクエストヘッダに埋め込まれているので、それを確認することもできます。

念のため – データを解析する前に、リクエストのヘッダをチェックします。

リクエストを処理する場合 – flaskrequest モジュールを使用すると、HTTP リクエストを表現することができます。

POST リクエストのボディは、リクエスト自体から直接抽出することができ、エンコーディングに応じて – 適切なフィールドにアクセスすることができます。

  • request.json または request.get_json() -)
  • request.form
  • request.data

request.jsonapplication/json という content-type でリクエストされた JSON を表す。

あるいは、 request.get_json() メソッドを利用することもできます。

フィールドにアクセスしても、メソッドにアクセスしても、受信した JSON に含まれる key-value のペアを dict として返します。

注意: json フィールドと get_json() メソッドは、POST リクエストの Content-Type が application/json に設定されているときのみ動作します。

JSON フォーマットの文字列の場合、この方法は失敗し、結果として None という値が返されます。

もしクライアントが適切にエンコードされたデータを送信するように強制できない場合は、入力された文字列をJSONに変換することができます。

このガイドの後半で説明します。

request.form は、ウェブフォームから取得した multipart/form-data データを表します。

request.data は、入力されたデータを文字列で表現したものである。

一般的には、クライアントが期待するcontent-typeを強制的に送信できない場合に、この表現を使ってJSONに変換することになるでしょう。

POST JSONを取得する

まずはJSONから始めましょう。

これはAPI間でデータを転送するために最もよく使われるフォーマットだからです。

ここでは、/post_jsonエンドポイントで POST リクエストを受け取るシンプルなルートハンドラを作成します。

リクエストのヘッダが application/json ペイロードとして適切にアノテーションされている場合にのみ、 json フィールドに値が格納されることを覚えておいてください。

ここでは、ヘッダーから ‘Content-Type’ を取得し、ボディが本当に application/json フォーマットであるかどうかを確認します。

もしそうでなければ、リクエストから JSON を抽出することはせず (抽出に失敗します)、エラーメッセージが返されます。

from flask import Flask, request
# ...
@app.route('/post_json', methods=['POST'])
def process_json():
    content_type = request.headers.get('Content-Type')
    if (content_type == 'application/json'):
        json = request.json
        return json
    else:
        return 'Content-Type not supported!'


もし今エンドポイントに POST リクエストを送ると、json が返されます。

$ curl -X POST -H "Content-type: application/json" -d "{"firstName" : "John", "lastName" : "Smith"}" "localhost:5000/post_json"


注意: 使用しているOSやシェルによっては、"の代わりに'を使用したり、“のようなエスケープ文字を完全にスキップしたりすることがあります。

この結果、以下のようになります。

{"firstName":"John","lastName":"Smith"}


すごい! では、-H引数を別の型にして、検証ステップがうまくいくかどうか試してみましょう。

$ curl -X POST -H "Content-type: multipart/form-data" -d "{"firstName" : "John", "lastName" : "Smith"}" "localhost:5000/post_json"


この結果は

Content-Type not supported!


別の方法として、 get_json() も同じように動作します。

from flask import Flask, request
# ...
@app.route('/post_json', methods=['POST'])
def process_json():
    content_type = request.headers.get('Content-Type')
    if (content_type == 'application/json'):
        json = request.get_json()
        return json
    else:
        return 'Content-Type not supported!'


文字列からPOST JSONを取得する

ここまででリクエストを送信したのは私たちなので、適当に content-type を変更する自由がありました。

時には、JSON 形式のリクエストに正しい content-type が割り当てられていないことがあります。

その場合、 jsonget_json() は受信した本文を JSON としてパースせず、結局は None となり、そこから何も取り出すことができません。

このような場合、 json モジュールを使用して、受け取った文字列を辞書 (key-value ペア) にロードすることができます。

モジュールをインポートして、受信した request.data を変換してみましょう。

from flask import Flask, request, json
# ...
@app.route('/post_json', methods=['POST'])
def process_json():
    data = json.loads(request.data)
    return data


これで、 text/plain エンコードされたボディを送信しても、 application/json エンコードされたボディを送信しても、 json モジュールは入力を処理することができます。

もし、これらのリクエストのどちらかを送信してみると、どちらも同じレスポンスが返ってくるでしょう。

$ curl -X POST -H "Content-type: application/json" -d "{"firstName" : "John", "lastName" : "Smith"}" "localhost:5000/post_json"
$ curl -X POST -H "Content-type: text/plain" -d "{"firstName" : "John", "lastName" : "Smith"}" "localhost:5000/post_json"


これらの結果は

{"firstName":"John","lastName":"Smith"}


POSTフォームの取得

When filling out forms – you have a series of inputs, and their corresponding labels. Under the hood – these are all just key-value pairs:

username=user_input
password=user_input_2
...


This is typically derived from the front-end – usually an HTML page with a <form> tag with several <input/> fields within it. You can also send form data via curl as:

$ curl -X POST -H "Content-type: multipart/form-data"  -F "username=john" -F "password=doe" "localhost:5000/post_form"


Or, you can collapse all of the fields into a single argument:

$ curl -X POST -H "Content-type: multipart/form-data"  -F "username=john&amp;password=doe" "localhost:5000/post_form"


In general – you’ll be working with actual forms though, and a form we would be working with looks like:

<form action="/post_form" enctype="multipart/form-data" method="POST">
<input name="username" type="text"/>
<input name="password" type="password"/>
</form>


The name of each <input/> is mapped as the key to a value input by the user. The form extracted from the request object is yet another dict – and you can access the fields individually easily:

from flask import Flask, request
# ...
@app.route('/post_form', methods=['POST'])
def process_form():
    data = request.form
    print(data['username'])
    print(data['password'])    
    return data


When we send a request via the console – the dictionary containing the key-value pairs is returned (which is then formatted again, as JSON):

{"password":"doe","username":"john"}


And on the server-end – the inputs for these two fields have been printed, right beneath the log for the incoming request

127.0.0.1 - - [09/Dec/2021 00:24:32] "POST /post_form HTTP/1.1" 200 -
john
doe


Naturally, instead of just printing the values to the console – you would validate the data, create a user, and persist them in the database. あるいは、クラスを使用する前に、この方法でクラスのフィールドにデータを入力することもできます。

結論

このガイドでは、Flask で HTTP POST リクエストを処理する方法について見てきました。

JSON データを受信する方法と、自動的にピックアップされない文字列で表現された JSON を処理する方法についても取り上げました。

最後に、フォームデータについて説明します。

</form

タイトルとURLをコピーしました