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-Typeapplication/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"}

こんな感じで、と。

MySQLで、接続が平文なのかSSL/TLSを使っているのかを確認する

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

SSL/TLS接続を受け付けられるMySQLサーバーを立てた時に、クライアントの接続が平文なのか、SSL/TLSを使っているのか
確認する方法はないかな?と。

環境

今回の環境は、こちら。

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.20    |
+-----------+
1 row in set (0.00 sec)

確認方法

すべての接続に対して確認する場合

以下のSQLで行います。

select
  status_by_thread.variable_value as tls_version,
  status_by_thread2.variable_value as cipher,
  threads.processlist_user as user,
  threads.processlist_host as host 
from performance_schema.status_by_thread as status_by_thread
join performance_schema.threads as threads
  on threads.thread_id = status_by_thread.thread_id
join performance_schema.status_by_thread as status_by_thread2
  on status_by_thread2.thread_id = threads.thread_id
where status_by_thread.variable_name = 'Ssl_version'
  and status_by_thread2.variable_name = 'Ssl_cipher'
order by tls_version;

実行例。

+-------------+------------------------+-----------+-------------+
| tls_version | cipher                 | user      | host        |
+-------------+------------------------+-----------+-------------+
|             |                        | user1  | xxx.xxx.xxx.xxx   |
| TLSv1.3     | TLS_AES_256_GCM_SHA384 | user2 | xxx.xxx.xxx.xxx |
| TLSv1.3     | TLS_AES_128_GCM_SHA256 | user3 | xxx.xxx.xxx.xxx |
+-------------+------------------------+-----------+-------------+
3 rows in set (0.00 sec)

もうひとつ

+-------------+------------------------+-----------+-------------+
| tls_version | cipher                 | user      | host        |
+-------------+------------------------+-----------+-------------+
|             |                        | user1  | xxx.xxx.xxx.xxx   |
|             |                        | user2 | xxx.xxx.xxx.xxx |
| TLSv1.3     | TLS_AES_256_GCM_SHA384 | user3 | xxx.xxx.xxx.xxx |
+-------------+------------------------+-----------+-------------+

SSL/TLS通信を行っている場合は、SSL/TLSのバージョンと、使用しているアルゴリズムが表示されます。

Performance Schemaからの情報ですね。MySQL内のスレッドおよび、スレッドのステータス変数を利用しています。

MySQL :: MySQL 8.0 Reference Manual :: 26.12.15 Performance Schema Status Variable Tables

MySQL :: MySQL 8.0 Reference Manual :: 26.12.19.7 The threads Table

現在の接続に対して確認する場合

show statusで行います。

SSL/TLS通信を行っている場合。

mysql> show status where variable_name = 'Ssl_version' or variable_name ='Ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
| Ssl_version   | TLSv1.3                |
+---------------+------------------------+
2 rows in set (0.00 sec)

平文で行っている場合。

mysql> show status where variable_name = 'Ssl_version' or variable_name ='Ssl_cipher';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Ssl_cipher    |       |
| Ssl_version   |       |
+---------------+-------+
2 rows in set (0.25 sec)

こちらは、サーバーステータス変数を使用しています。

MySQL :: MySQL 8.0 Reference Manual :: 13.7.7.35 SHOW STATUS Statement

MySQL :: MySQL 8.0 Reference Manual :: 5.1.10 Server Status Variables

Ssl_version

The SSL protocol version of the connection (for example, TLSv1). If the connection is not encrypted, the value is empty.

Ssl_cipher

The current encryption cipher (empty for unencrypted connections).