はじめに
PythonのWebフレームワークといえばDjangoやFlask等が有名だと思いますが、Pythonで手軽にサクッとAPIサーバーを立ててみたいという時には、bottleはかなり有効な選択肢になります。本記事では、PythonのWebフレームワークの一つであるbottleを用いてAPIサーバーを立てる時の基本的な書き方について説明します。
実行環境
macOS Mojave 10.14.6
Python 3.7.3
bottle 0.12.17
インストール
Python の仮想環境まではできているとします。
bootle のインストールは普通に
pip install bottle
でできます。
Hello world
from bottle import get, run
@get("/hello")
def hello():
return "Hello, world."
if __name__ == '__main__':
run(host="localhost", port=8080)
これを実行し、ブラウザから http://localhost:8080/hello にアクセスすると画面上に Hello, world. の文字が表示されます。
ルーティング
このソースコードでは、@get
デコレータで /hello
へのGETリクエストに対する処理を指定しています。その他のHTTPメソッドについては、@post
、@put
、@delete
デコレータを用いることでそれぞれPOSTメソッド、PUTメソッド、DELETEメソッドに対する処理を指定することができます。
また、以下のように動的なルーティングを指定することもできます。
@get("/hello/<name>")
def hello(name):
return f"Hello, {name}."
この例だと、http://localhost/hello/takeshi にアクセスすると画面に Hello, takeshi. と表示されます。パスパラメータを関数の引数として受け取れるわけです。
リクエストの情報を受け取る
bottle.request
を用いると、リクエストに関する各種情報を扱えます。
from bottle import get, request
@get("/hello")
def hello():
limit = request.params.get("limit")
body = request.json
header = request.get_header("Content-Type")
request.params
はクエリパラメータの一覧を返します。
返り値の型は bottle.FormDict
で、dict
型とほとんど同じように使えます。
dict
にしたければ dict(requset.params)
とすることもできます。
request.json
はリクエストヘッダに Content-Type: application/json
が指定されているとき、リクエストボディを dict
で返します。
Content-Type
が application/json
でないときは None
が返ります。
Content-Type
にかかわらず request.body
でリクエストボディを取得することができますが、request.json
は dict
型を返してくれて扱いやすいので、 リクエストボディは json
で受け取るようにするのが良いと思います。
request.get_header(name)
はリクエストヘッダを取得します。
request.headers
ですべてのリクエストヘッダに一気にアクセスすることもできます。
HTTPレスポンスを返す
ここまでの例では関数は文字列を返していましたが、APIサーバーでは bottle.HTTPResponse
クラスのオブジェクトを返すほうが良いです。
from bottle import get, HTTPResponse
@get("/hello")
def hello():
header = {"Content-Type": "application/json"}
body = {"message": "OK"}
res = HTTPResponse(status=200, body=body, headers=header)
return res
HTTPResponse
オブジェクトはステータスコードとレスポンスボディとレスポンスヘッダを渡して生成します。
レスポンスボディとレスポンスヘッダは後でつけることもできます。
ステータスコードは省略するとデフォルトのステータスコードが付与され、多くの場合 200
となるようです。
res = HTTPResponse()
res.body = {"message": "OK"}
res.set_header("Content-Type", "application/json")
# 上記と同じ res ができる
おまけ:Herokuにデプロイする時は
Herokuではポートを動的に用意するらしいので、ポートの設定は環境変数を使って行います。具体的には、os
モジュールをインポートして run
関数を以下のように書き換えるだけです。
run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
おわりに
以上、bottleを使ってAPIサーバーを立てる時のよく使われると思われる書き方を一通りまとめてみました。
また他に何かあれば追記します。
参考リンク
Bottle: Python Web Framework(公式)
BottleのRequest/Responseオブジェクトをマスター
Bottleを使って書いたWebアプリをHerokuに置くときにrun()を書き換えるのはなんで?