31
28

More than 5 years have passed since last update.

Python3.6とBottleでRESTful APIサーバを構築する

Last updated at Posted at 2018-01-29

最近Python3.6を勉強し始めました。
チュートリアル等を読んでいますが、普段はApache GroovyGrailsを使って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として、リストの中に辞書を突っ込むようにしました。

bottle-sample.py
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スクリプトのサクサク動くこの感じはかなり素敵だな感じました。

31
28
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
28