CLOVER🍀

That was when it all began.

Flaskで、REST APIっぽく遊ぶ

これは、なにをしたくて書いたもの?

以前に、Flask RESTfulを使ってみたのですが、JSONをやり取りするのに素のFlaskでもそんなに困らないのでは?と思いまして。

Flask-RESTful — Flask-RESTful 0.3.8 documentation

Flask RESTfulを試す - CLOVER🍀

って、前のエントリの最後にも、そんなことを書いていましたね。前のエントリで書いた内容を、Flaskのみでちょっと
試してみましょうか。

環境

今回の環境は、こちらです。

$ python3 -V
Python 3.8.2

Flaskをインストール。

$ pip3 install Flask

バージョン。

$ pip3 freeze
click==7.1.2
Flask==1.1.2
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
Werkzeug==1.0.1

まずは雛形を

まずはコードの雛形を作りましょう。

こんな感じで用意しました。
index.py

from datetime import datetime

from flask import Flask, jsonify, request

app = Flask(__name__)

#### ここに、いろいろ書く

if __name__ == '__main__':
    app.run(debug = True)

以降は、この部分にいろいろ追記していきたいと思います。

#### ここに、いろいろ書く

とりあえず、JSONを返してみよう

jsonifyを使えばよいみたいです。

flask.json.jsonify

こんな感じで。

@app.route('/')
def hello_world():
    return jsonify(message = 'Hello Flask!', now = datetime.now())

jsonifyを使うと、Content-Typeがapplication/jsonとなってくれるところがポイントです。

$ curl -i localhost:5000
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 65
Server: Werkzeug/1.0.1 Python/3.8.2
Date: Thu, 17 Sep 2020 13:37:23 GMT

{"message":"Hello Flask!","now":"Thu, 17 Sep 2020 22:37:23 GMT"}

URLパスに変数を入れる

Applicationオブジェクトのrouteに、ふつうに書けるようです。

Application Object

URL Route Registrations

こんな感じで。

@app.route('/var/<string:id>')
def with_variable(id):
    return jsonify(request_id = id)

変数は、メソッドの引数として渡されます。

確認。

$ curl -i localhost:5000/var/12345
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 28
Server: Werkzeug/1.0.1 Python/3.8.2
Date: Thu, 17 Sep 2020 13:51:08 GMT

{
  "request_id": "12345"
}

QueryStringやJSONを受け取る

QueryStringは、Requestから取得することができます。

Incoming Request Data

QueryStringそのものを取得する場合は、query_stringを使います。bytestringで返ってくるので、今回は文字列にするように
decodeしています。

パラメーターとして取得したい場合は、argsを使います。

args

こんな感じで。

@app.route('/get')
def with_query_string():
    return jsonify(
        query_string = request.query_string.decode('utf-8'),
        request_param = request.args.get('param')
    )

確認。

$ curl -i localhost:5000/get?param=value
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 65
Server: Werkzeug/1.0.1 Python/3.8.2
Date: Thu, 17 Sep 2020 13:56:38 GMT

{
  "query_string": "param=value", 
  "request_param": "value"
}

最後に、JSONを受け取ってみましょう。HTTPメソッドも、POSTに限定してみます。

add_url_rule

JSONリクエストを取得するには、get_jsonを使うのがよさそうです。

get_json

force = Trueにしておくと、Content-Typeに関係なくJSONとして扱ってくれます。デフォルトでは、application/jsonとしなければ
JSONとして認識してくれません。

@app.route('/post', methods = ['POST'])
def with_json():
    json = request.get_json(force = True)
    return jsonify(request_json = json, request_name = json['name'])

確認。

$ curl -i localhost:5000/post -d '{"name": "value"}'
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 76
Server: Werkzeug/1.0.1 Python/3.8.2
Date: Thu, 17 Sep 2020 14:29:16 GMT

{
  "request_json": {
    "name": "value"
  }, 
  "request_name": "value"
}

ざっと、前に書いた内容は確認できました。とりあえず、基本的なことはできるのではないでしょうか?

WSGIサーバーで動かしてみる

最後に、WSGIサーバー…今回もGunicornで動かしてみます。

$ pip3 install gunicorn

バージョン。

$ pip3 freeze | grep gunicorn
gunicorn==20.0.4

起動。

$ gunicorn index:app
[2020-09-17 23:30:43 +0900] [12500] [INFO] Starting gunicorn 20.0.4
[2020-09-17 23:30:43 +0900] [12500] [INFO] Listening at: http://127.0.0.1:8000 (12500)
[2020-09-17 23:30:43 +0900] [12500] [INFO] Using worker: sync
[2020-09-17 23:30:43 +0900] [12502] [INFO] Booting worker with pid: 12502

確認。

$ curl -i localhost:8000/get?param=value
HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Thu, 17 Sep 2020 14:30:53 GMT
Connection: close
Content-Type: application/json
Content-Length: 55

{"query_string":"param=value","request_param":"value"}

こんな感じで、と。