BottleでWeb APIを作成する

BottleはPythonの軽量Webフレームワーク。
サーバサイドのPython製フレームワークではDjangoやFlaskが有名ですが、中でも1ファイルで実装されているというシンプルな構成の(マイクロ)フレームワークなのだそうです。

手軽にWeb APIを作りたいと思い立ち、今回はBottleを選択。データ形式はjsonで。
基本jsonデータを送受信できればいいので、テンプレートエンジンなどWebページ(html)関連の機能は利用しません。

インストールは公式からファイルをダウンロードするか、またはいつものpipで可能。

ダウンロードする場合:

pipの場合:

ルーティングの基本

本題の前にとりあえず書いてみます。
マイクロフレームワークだけあってMVCなどモジュール構成などのお約束は緩め。逆に言うと、プログラマが設計しなければならないことが多いと言えます。

制約というわけではありませんが、ここでは機能別にモジュールを分けて実装していきます。
上のように、サーバを立ち上げるapp.py、ルーティングを記述するroutes.py、ロジック部分のutils.pyの3ファイル構成としました。
とりあえずは解説のため書いたので、この段階ではおそらくちゃんと動きません(後半で一応動くものを書きます)。

app.py

サーバ、ポートの設定。ルーティングを記述するroutesモジュールをインポートしておきます。
上の例で、サーバの設定(host='localhost')は、ローカルのみアクセスを許可する指定です。
設定にはサブネットアドレスを書くなどいくつかパターンがあり、他のマシンからも無制限に繋ぎたければhost='0.0.0.0'とします。
ソースを見た限り、ポート番号のデフォルトは8080のようです。

routes.py

メソッドの書き方は2通りあり、@routeとしてmethodを指定するか、または@getのようにメソッドを直接書くか。前者のほうが後々メソッドを追加できる点で汎用的かも。
ここでやっているのは単純にルーティングに応じて処理内容(utils.py)の関数を呼び出しているだけです。404などhttpエラーステータスを返したければabortを使うと楽。

utils.py

やりたい処理の本体。後ほどちゃんと作ります。

app.pyを呼んでやればローカル&指定したポートでサーバが立ち上がります。
メッセージにもある通りブラウザでURLを開けば(もちろんwgetとかでも可)動作が確認できます。
ファイアウォールが有効な場合などポートを開放する必要があるかも。

APIの実装

さて、ここからはちゃんと動くものを作ります。
といっても、機能的にはあまり意味がないアプリケーションです(長くなってしまったので、意味があるものは別記事で)。
実装したいAPIの設計に従って、routes.pyにURIやメソッドを、utils.pyに処理の実体を書いていきます。
以下の例では、ファイル構成は前半と同じですが、内容を書き換えています。

サーバの起動設定(app.py)

前掲の例と特に大きな変更なし。アクセス元クライアントをセグメントで制限しない設定(host='0.0.0.0')、ポートをデフォルト(8080)にしてみました。

ルーティング(routes.py)

HTTPメソッド、URIとクエリで処理を分岐させます。

複数のメソッドを定義するため、@routemethodに配列を渡し、対応する処理はrequest.methodで条件分岐させます。

クエリパラメータ(この例ではPOST時の/api/item?(name)=xxx)はrequest.query.(name)で取得できます。

もちろんダイナミックにルーティングさせる(この例ではPUTのURL<item_id>の部分)こともでき、ここでは使っていませんが正規表現も使えるらしい。

レスポンスのContent-Typeに'application/json'をセットし、JSON文字列(string型)を返しています。

ロジック

ルーティングさえ押さえておけば、あとは普段のPythonの知識で自由にロジックを組むことができます。

この例ではutils.pyがjson文字列を返します。

いろいろ試してみたのですが、サーバが受信したデータ、言い換えればクライアントが送信したボディ(request.bodyで取り出したもの)はByteストリームで渡ってくるようです。そこで、リクエストのボディ(クライアントからjsonデータを渡したもの)から、json.load(f)でオブジェクトを取り出しています。

実行

前半と同じコマンドpython app.pyで、とりあえず動かすことはできるはず。
ためしにPOST, PUTしてみるとこんな感じ。

つづきは長くなってしまったので別記事で。