Flask-Restless を試してみる
API サーバとして Flask を使う場合にコードが簡略できそうなので、Flask-Restless を試してみた。
同様なプロダクトとして、Flask-Restful があるけど、Flask-Restless を選んでみたのは view を書かなくてよさそうだったから。
# 逆に言えば「おまかせ」になってしまう可能性もある
前提としてアップロードした写真を表示する Web アプリケーションで、以下のルーティングを想定する。
http://example.com/pictures | 写真一覧を html で返す |
http://example.com/pictures/:id | :id の写真情報を html で返す |
http://example.com/api/pictures | 写真一覧を JSON で返す |
http://example.com/api/pictures/:id | :id の写真情報を JSON で返す |
app.py
# -*- coding: utf-8 -*- from flask import Flask, request, render_template from pictapp.db import mysession from pictapp.extensions import restless from pictapp.views import views from pictapp.views.api import register_api def create_app(): app = Flask(__name__) restless.init_app(app, session=mysession) for view in views: app.register_blueprint(view) apis = register_api() [app.register_blueprint(api) for api in apis] return app if __name__ == '__main__': create_app().run(debug=True)
extensions.py
from flask.ext.restless import APIManager __all__ = ['restless'] restless = APIManager()
views/__init__.py
from pictapp.views.index import app views = (app,)
views/api.py
from pictapp.extensions import restless from pictapp.models import Picture def register_api(): return (restless.create_api_blueprint(Picture, methods=['GET']),)
db.py
from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import scoped_session, session maker engine = create_engine('sqlite:////tmp/testdb.sqlite', convert_unicode=True) Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) mysession = scoped_session(Session) Base = declarative_base() Base.metadata.bind = engine
modes.py
from sqlalchemy import Column, Integer, String from pictapp.db import Base class Picture(Base): __tablename__ = 'pictures' id = Column(Integer, primary_key=True) name = Column(String(254), nullable=False) title = Column(String(254), nullable=False) description = Column(String(254), nullable=False) def __init__(self, name, title, description): self.name = name self.title = title self.description = description def __repr__(self): return "<Picture({0}, {1}, {2})>".format( self.id, self.name, self.title, self.description )
だいぶ簡略したけど雰囲気はこんな感じ。
サンプルコードとかは app.py とかに直接 restless の create_api_blueprint() とかを書いてあるけど、モデルの追加とか普通にあるし、イチイチ Applictaion factory である app.py とかの変更をしたくない。
そのため views/api.py という所に view として実装してみた。
モデルを api に追加したくなったら、views/api.py の return しているタプルに追加すれば自動的に反映するようにしてみた。
あとサンプルは Flask-SQLAlchemy を使うコードがあるけど、素の SQLAlchemy も使える(ドキュメントに書いてある)。
これでブラウザで http://examples/api/pictures*1 にアクセスすると SQLite3 に格納されたデータが全て応答する。
{ "num_results": 5, "objects": [ { "description": "test", "id": 1, "name": "717f303c.jpg", "title": "sample" }, { "description": "test", "id": 2, "name": "62744a28.jpg", "title": "sample" }, { "description": "bbbb", "id": 3, "name": "896844eb.jpg", "title": "aaa" }, { "description": "bbbb", "id": 4, "name": "62744a28_1.jpg", "title": "aaa" }, { "description": "bbb", "id": 5, "name": "4a8b6d8f.jpg", "title": "aaa" } ], "page": 1, "total_pages": 1 }
意外と簡単になった。
特に API の場合 view を一切書かなくても良さそう。
POST や PUT のような作成/更新なものも preprocessor や postprocessor を使って定義してやればある程度自由度が高いものが出来そう。
Customizing the ReSTful interface — Flask-Restless 1.0.0b2.dev documentation