これは、なにをしたくて書いたもの?
Pythonで、簡単にREST APIを作れるフレームワークを知りたいなと思いまして。
PythonでのWebフレームワークといえば、DjangoとFlaskが有名みたいですが、Flask RESTfulが入りやすそうだったので、こちらを
試してみることにしました。
Flask-RESTful — Flask-RESTful 0.3.7 documentation
環境
今回の環境は、こちら。
$ python3 -V Python 3.6.8
Flask RESTfulのインストール
まずは、インストール。
Installation — Flask-RESTful 0.3.6 documentation
$ pip3 install flask-restful
インストールされたFlask RESTfulは0.3.7。
$ pip3 freeze aniso8601==7.0.0 Click==7.0 Flask==1.1.1 Flask-RESTful==0.3.7 itsdangerous==1.1.0 Jinja2==2.10.1 MarkupSafe==1.1.1 pkg-resources==0.0.0 pytz==2019.2 six==1.12.0 Werkzeug==0.15.5
なのですが、参照するドキュメントのバージョンは固定したいので、リンク上は0.3.6のドキュメントを書いていくことにします…。
Hello World
こちらを見ながら、Hello World。
Quickstart — Flask-RESTful 0.3.6 documentation
hello_flask.py
from flask import Flask from flask_restful import Api, Resource app = Flask(__name__) api = Api(app) class HelloWorld(Resource): def get(self): return { 'message': 'Hello World' } api.add_resource(HelloWorld, '/') if __name__ == '__main__': app.run(debug = True)
app = Flask(__name__) api = Api(app)
これに、Resourceクラスを登録するようですね。第2引数が、ルーティングのパスのようです。
api.add_resource(HelloWorld, '/')
作成するResourceのサブクラスは、HTTPメソッドに応じてget、postメソッドなどを作成するようです。
class HelloWorld(Resource): def get(self): return { 'message': 'Hello World' }
起動部分。
if __name__ == '__main__': app.run(debug = True)
この「debug = True」は、以下あたりを見ればよさそうです。コードを修正した時の、自動リロードもやってくれるみたいです。
Werkzeug — Werkzeug Documentation (0.15.x)
今回は、あまり追わず。
では、起動してみます。
$ python3 hello_flask.py * Serving Flask app "hello_flask" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 980-333-426
確認。
$ curl localhost:5000 { "message": "Hello World" }
動きましたね。
URLパスに、変数を設定する
URLパスに、変数を入れることもできるようです。
ちょっと試してみましょう。
先ほどのファイルに、追加でResourceを足してみます。
class VariableRouting(Resource): def get(self, id): return { 'id': id } api.add_resource(HelloWorld, '/') api.add_resource(VariableRouting, '/var/<string:id>')
「<型:名前>」でルーティングの設定時にパス指定をして、Resourceのメソッドで受け取るようです。
確認。
$ curl localhost:5000/var/123456 { "id": "123456" }
QueryStringやHTTPボディを扱ってみる
QueryStringやHTTPボディを扱うには、FlaskのAPIを使えばいいみたいです。
こんな感じで、Flaskのrequestを使います。
server.py
from flask import Flask, request from flask_restful import Api, Resource, reqparse app = Flask(__name__) api = Api(app) parser = reqparse.RequestParser() class QueryResource(Resource): def get(self): query_string = request.query_string param = request.args.get('param') return { 'query_string': query_string.decode('utf-8'), 'param': param } class PostResource(Resource): def post(self): json = request.get_json(force = True) return { 'json_request': json } api.add_resource(QueryResource, '/get') api.add_resource(PostResource, '/post') if __name__ == '__main__': app.run(debug = True)
QueryStringを扱う場合。
def get(self): query_string = request.query_string param = request.args.get('param') return { 'query_string': query_string.decode('utf-8'), 'param': param }
JSONデータを扱う場合。
def post(self): json = request.get_json(force = True) return { 'json_request': json }
request.get_jsonの「force = True」を付けない場合は、Content-Typeにapplication/jsonを指定しないとJSONを認識してくれません。
確認。
$ curl localhost:5000/get?param=value { "query_string": "param=value", "param": "value" } $ curl localhost:5000/post -d '{"name":"value"}' { "json_request": { "name": "value" } }
OKそうです。
WSGIサーバーで動かしてみる
最後に、WSGIサーバーで動かしてみましょう。
今回は、Gunicornを使うことにします。
インストール。
$ pip3 install gunicorn
バージョン。
gunicorn==19.9.0
起動方法としては、こんな感じで。
$ gunicorn hello_flask:app
拡張子なしのファイル名の後に指定するのは、Flaskインスタンスを格納した変数名みたいです。
app = Flask(__name__)
起動。
$ gunicorn hello_flask:app [2019-08-14 23:53:35 +0900] [26331] [INFO] Starting gunicorn 19.9.0 [2019-08-14 23:53:35 +0900] [26331] [INFO] Listening at: http://127.0.0.1:8000 (26331) [2019-08-14 23:53:35 +0900] [26331] [INFO] Using worker: sync [2019-08-14 23:53:35 +0900] [26334] [INFO] Booting worker with pid: 26334
確認。
$ curl -i localhost:8000 HTTP/1.1 200 OK Server: gunicorn/19.9.0 Date: Wed, 14 Aug 2019 14:53:56 GMT Connection: close Content-Type: application/json Content-Length: 27 {"message": "Hello World"}
OKそうです。
これで、ちょっとしたREST APIなら書けそうですね。
ところで書き始めた後に気づいたのですが、素のFlaskでも実はけっこう書けるのでは?と気づきました…。
Flask RESTfulの場合は、エンドポイントを関数ではなくResourceクラスとして表現できることと、ルーティングの設定を
まとめられるとかがポイントでしょうかね。
まあ、いいや…。