最近Python3.6を勉強し始めました。
チュートリアル等を読んでいますが、普段はApache GroovyとGrailsを使ってWebアプリケーションの開発運用をしているので、どうしてもWeb周りのコードで色々実験してみたくなります。
Djangoがやはり有名なものだと思うのですが、そこまで行くとちょっとDjango自体の理解に時間がかかるし。。。
ということで、Python用のMicro web frameworkと謳われているBottleを試してみましたので、その備忘録としてこの記事を書いています。
仮想環境の作成
Python3.6では、標準で仮想環境を以下のように作成できるようです。
python -m venv $HOME/work/bottle
source $HOME/work/bottle/bin/activate
Bottleのインストール
上記ですでに仮想環境に入っているので、以下のコマンドを叩くだけでOKです。
pip install -U bottle
コード
データベースを用意するのが面倒くさかったので、とりあえず簡易DBとして、リストの中に辞書を突っ込むようにしました。
from bottle import route, run
from bottle import post, get, put, delete, request, response
import json
books = [
{'id': 1, 'title': 'book 1'},
{'id': 2, 'title': 'book 2'},
{'id': 3, 'title': 'book 3'},
]
@get('/books')
def books_list():
response.headers['Content-Type'] = 'application/json'
response.headers['Cache-Control'] = 'no-cache'
return json.dumps(books)
@get('/books/<id:int>')
def a_book(id):
search = filter(lambda book: book['id'] == id, books)
obj = next(search, None)
# https://bottlepy.org/docs/dev/tutorial.html#generating-content
# returnする値が辞書(もしくはそのサブタイプ)場合、Bottoleが自動的にレスポンスヘッダにapplication/jsonを付けてくれる!
if obj is not None:
return obj
else:
response.status = 404
return {}
@post('/books')
def create_book():
# 泥臭い以下のような書き方もできるけど。。。?
#try:
# body = json.load(request.body)
#except:
# raise ValueError
#books.append(body)
# HttpリクエストヘッダのcontentTypeが'application/json'であれば、requset.jsonが利用できる。
# https://bottlepy.org/docs/dev/tutorial.html#json-content
books.append(request.json)
return request.json
@put('/books/<id:int>')
def update_book(id):
search = filter(lambda book: book['id'] == id, books)
obj = next(search, None)
if obj is not None:
index = books.index(obj)
books[index] = request.json
return request.json
else:
response.status = 404
return {}
@delete('/books/<id:int>')
def update_book(id):
search = filter(lambda book: book['id'] == id, books)
obj = next(search, None)
if obj is not None:
index = books.index(obj)
del books[index]
return {}
else:
response.status = 404
return {}
run (host='localhost', port=8081, debug=True, reloader=True)
実際に試す
後は普通にcurlコマンドを叩けば動作を確認することが出来ます。
まずはpython bottle-sample.py
でサーバを起動します。
[koji:~]$ curl http://localhost:8081/books
[{"id": 1, "title": "book 1"}, {"id": 2, "title": "book 2"}, {"id": 3, "title": "book 3"}]%
[koji:~]$ curl http://localhost:8081/books/3
{"id": 3, "title": "book 3"}%
[koji:~]$
ちゃんとデータが取れました。
ではPOSTでデータを追加してみます。
[koji:~]$ curl -H 'Content-Type:application/json' -d '{"id": 4, "title": "book4"}' http://localhost:8081/books
{"id": 4, "title": "book4"}%
[koji:~]$
[koji:~]$ curl http://localhost:8081/books
[{"id": 1, "title": "book 1"}, {"id": 2, "title": "book 2"}, {"id": 3, "title": "book 3"}, {"id": 4, "title": "book4"}]%
[koji:~]$
[koji:~]$ curl http://localhost:8081/books/4
{"id": 4, "title": "book4"}%
[koji:~]$
問題なく新しくデータが追加できました。
それでは今度は既存のデータをアップデートしてみます。
[koji:~]$ curl -X PUT -H 'Content-Type:application/json' -d '{"id": 2, "title": "Book2 second edition"}' http://localhost:8081/books/2
{"id": 2, "title": "Book2 second edition"}%
[koji:~]$ curl http://localhost:8081/books
[{"id": 1, "title": "book 1"}, {"id": 2, "title": "Book2 second edition"}, {"id": 3, "title": "book 3"}, {"id": 4, "title": "book4"}]%
[koji:~]$ curl http://localhost:8081/books/2
{"id": 2, "title": "Book2 second edition"}%
[koji:~]$
更新出来ました。
では最後に削除してみます。
[koji:~]$ curl -X DELETE http://localhost:8081/books/3
[koji:~]$
[koji:~]$ curl http://localhost:8081/books
[{"id": 1, "title": "book 1"}, {"id": 2, "title": "Book2 second edition"}, {"id": 4, "title": "book4"}]%
[koji:~]$ curl http://localhost:8081/books/3
[koji:~]$
削除も動作しています。
まとめ
まだPython力が足りないので、リスト周りの検索方法、そしてエラー処理の部分がだいぶガバガバになってしまっています。
ただ、今までJVM畑で過して来たので、Pythonスクリプトのサクサク動くこの感じはかなり素敵だな感じました。