メインコンテンツへスキップ
  1. 第10講 Webアプリケーション(Docker)/

Flask

Flask HTTP REST API
目次

Flask と REST API
#

Flask は Python で一番人気のある Web フレームワークです. 小規模な Web アプリケーションを作るのに適していることから,マイクロフレームワークと呼ばれることもあります. ここでは,Flask を使って,REST API を提供する Web アプリケーションを作成します.

REST API とは,Web サービスの一種で,HTTP プロトコルを使ってデータの送受信を行うものです. REST API は,リソース(データ)に対して,GETPOSTPUTDELETE などの HTTP メソッドを使って操作を行います. GET はリソースの取得,POST はリソースの作成,PUT はリソースの更新,DELETE はリソースの削除を行います. それぞれの HTTP メソッドを特定のURLに対して送信することで,リソースに対する操作を行うことができます. この特定のURLをエンドポイントと呼びます.

Hello REST World!
#

まずは,Flask で REST API を提供する Web アプリケーションを作成してみましょう. 単純に,GET メソッドでエンドポイント / でリクエストを受けると,Hello, REST World! というメッセージを返すだけの Web アプリケーションです.

まずは,Flask をインストールします. 以下のコマンドを実行してください.

pip3 install flask

次に,以下の Python スクリプト(hello_rest.py)を作成してください.

# hello_rest.py
from flask import Flask

app = Flask(__name__)

@app.route("/", methods = ["GET"])   # GET メソッドで / にアクセスされたときに hello() 関数を実行する.
def hello():                         # エンドポイントは / である.
    return "Hello, REST World!", 200 # 200 は HTTP ステータスコードで,成功を示す.

# ポート番号 5001 で Web アプリケーションを実行する.
app.run(port = 5001, debug = True, host = "0.0.0.0") 
# host = "0.0.0.0" の指定を忘れると,localhost からのアクセスしか受け付けなくなります.
# どこからでもアクセスできるようにするためには,host = "0.0.0.0" の指定が必要となります.

このスクリプトを実行したあと,ブラウザで http://localhost:5001/ にアクセスすると,Hello, REST World! というメッセージが表示されることを確認してください.

上記の hello 関数の前に書かれている @app.route("/", methods = ["GET"]) は,HTTP の GET メソッドで / にアクセスされたときに,hello() 関数を実行することを示しています. このような関数の前に書かれた @ から始まるものをデコレータと呼びます. 詳しくは補講 デコレータを参照してください. ここでは,Flask で特定の URL に,指定された HTTP メソッドでアクセスされたときに,どの関数を実行するかを指定するものであるという認識で問題ありません.

なお,Flask はデフォルトでポート番号 5000 で Web アプリケーションを実行しますが,macOS の場合,5000 はすでに使われています(Air Play Receiverが利用している). 同じ番号で異なるサービスは起動できないため,ここでは5001 を利用しています. app.run() のキーワード引数でポート番号を指定できます.

ポート番号 ポート番号とは,ネットワーク上でサービスを提供する窓口となる番号のことです. 1〜1023 まではWell-known ポートと呼ばれ,特定のサービスに割り当てられています. 例えば,80は HTTP サーバ,443 は HTTPS サーバ,22 は SSH サーバなどが割り当てられています. 1024 以上は任意のポート番号として利用できます. 上記の hello.py では 5001 をポート番号として指定しています.
i address already in use

もし,hello_rest.pyを実行したときに Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:5001 -> 0.0.0.0:0: listen tcp4 0.0.0.0:5001: bind: address already in use のようなエラーが表示された場合は,ポート番号がすでに利用されています. どのプログラムがポート番号を利用しているのかを調べるには,lsof を用いてください.sudo lsof -i :5001 5001番ポートを利用しているプロセス番号(PID)を調べ,kill <PID> でプロセスを終了してください.

REST API での引数の渡し方
#

REST API での,クライアントからのデータの渡し方は3通りあります. それぞれ,パスパラメータ,クエリパラメータ,リクエストボディです.

パスパラメータは,URL のパスに含まれるパラメータです. クエリパラメータは,URL の後ろに ? を付けて,key=value の形式でパラメータを渡します. リクエストボディは,リクエストのボディにデータを含めて送信します. ただし,リクエストボディを利用する場合は,HTTP メソッドは,POSTもしくはPUTである必要があります.

以下の例(hello_rest2.py)では,それぞれの方法でデータを受け取る方法を示します.

# hello_rest2.py
from flask import Flask, request

app = Flask(__name__)

@app.route("/", methods = ["GET"])  # GET メソッドで / にアクセスされたときに
def hello():                        # hello() 関数を実行する.
    name = request.args.get("name") # リクエストパラメータ name を取得する.
    if name:
        return f"Hello, {name} and REST World!", 200
    return "Hello, REST World!", 200

@app.route("/<name>", methods = ["GET"]) # パスパラメータとして name が与えられる.
def hello_name(name):                    # name は hello_name() 関数の引数として受け取る.
    return f"Hello, {name}!", 200

@app.route("/hello", methods = ["POST"]) # POST メソッドで /hello にアクセスされたときに 
def hello_post():                        # hello_post() 関数を実行する.
    name = request.form.get("name")      # リクエストボディの name を取得する.
    if name:
        return f"Hello, {name} and REST POST World!", 200
    return "Hello, REST POST World!", 200

# ポート番号 5001 で Web アプリケーションを実行する.
app.run(port = 5001, debug = True, host = "0.0.0.0") 
# host = "0.0.0.0" の指定を忘れると,localhost からのアクセスしか受け付けなくなります.
# どこからでもアクセスできるようにするためには,host = "0.0.0.0" の指定が必要となります.

上記プログラムを起動後に,以下のように実行すると,それぞれの結果が表示されます. もちろん,ブラウザから同様のURLにアクセスしても同じ結果が得られます. ただし,ブラウザのアドレスバーからは POST メソッドはリクエストを送信できませんので,最後の例は以下のように curlコマンドを利用してください.

$ curl http://localhost:5001/ # / にアクセスする.クエリパラメータなし.
Hello, REST World!
$ curl "http://localhost:5001/?name=John" # / にアクセスする.クエリパラメータ name に John を指定する.
Hello, John and REST World!               # ? は zsh では特殊文字なので,ダブルクォートで囲む.
$ curl http://localhost:5001/Jane         # /Jane にアクセスする.パスパラメータ name に John を指定する.
Hello, Jane!
$ curl http://localhost:5001/hello -X POST -d "name=Jane" # /hello に POST メソッドでアクセスする.
Hello, Jane and REST POST World!                          # リクエストボディに name=Jane を指定する.

curl コマンドは,-X オプションの後ろで HTTP メソッドを指定できます. -d オプションの後ろでリクエストボディを指定できます.

curl コマンドのオプションまとめ
#

  • -i, --include: レスポンスヘッダを表示する.
  • -v, --verbose: リクエストとレスポンスの詳細を表示する.冗長モード(verbose)にする.
  • -X <METHOD>, --request <METHOD>: HTTP メソッドを指定する.指定しなければ GET メソッドとなる.
  • -d <DATA>, --data <DATA>: <DATA>をリクエストボディに含めてリクエストを送信する.
  • -H <HEADER>, --header <HEADER>: リクエストヘッダに <HEADER> を追加する.