Flask と REST API #
Flask は Python で一番人気のある Web フレームワークです. 小規模な Web アプリケーションを作るのに適していることから,マイクロフレームワークと呼ばれることもあります. ここでは,Flask を使って,REST API を提供する Web アプリケーションを作成します.
REST API とは,Web サービスの一種で,HTTP プロトコルを使ってデータの送受信を行うものです.
REST API は,リソース(データ)に対して,GET
,POST
,PUT
,DELETE
などの 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()
のキーワード引数でポート番号を指定できます.
hello.py
では 5001 をポート番号として指定しています.
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>
でプロセスを終了してください.
- lsofコマンド入門 (qiita.com)
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>
を追加する.