歩数収集APIその②(歩数で競う!GoogleNestHubアプリの開発)

歩数で競う!GoogleNestHubアプリ開発
スポンサーリンク
スポンサーリンク

前回に引き続き、歩数収集APIの開発です。

前回までに歩数を管理するテーブルの作成まで行ったので、今回はそこに値を登録するPythonアプリを作成し、実際に値を入れるところまで行いたいと思います。

PythonでWEBアプリを作成する

PythonからPosgreSQLを利用する

※ここからはお使いのパソコンにPythonのインストールが完了している前提となります。まだの方はこちらを参考にしてください。

また、プログラム開発を行う際に統合開発環境(IDE)を用いるのが便利です。Visual Studio Codeの環境設定についてご紹介しているのでよかったら参考にしてください。

PythonからPosgreSQLに接続するにはは’psycopg2’というライブラリを用います。

psycopg2がインストールされていない場合は Anaconda Powershell Prompt 上でpip install psycopg2してください。

早速ソースコードを書いてみましょう。

#psycopg2のライブラリを読み込みます。
import psycopg2

#PosgreSQLに接続するための接続文字列です。
#postgresql://{username}:{password}@{host}:{port}/{database}の形式で記載します。
#ご自身の環境に合わせて変更してください。
DSN= "postgresql://postgres:password@localhost:5432/sampledb"

#PosgreSQLに接続してconnectionオブジェクトを取得します。
conn = psycopg2.connect(DSN)

#cursorオブジェクトを取得します。SQLの実行はこのcursorオブジェクトを用います。
cur = conn.cursor()

#SQLを実行します。insert文でstep_hist_rowテーブルに1件のレコードを追加しています。
#SQL文ではテキスト項目は 'で括る必要がありますが、このままだと文法的にエラーになるので、
#SQL文中の 'は\をつけてエスケープ処理をしてください。
cur.execute("insert into step_hist_row(user_name,step_date) values (\'tanupapa\',\'2001-10-02 20:38:40\');")

#insert文をコミット(確定)します。
conn.commit()

#cursorオブジェクトをクローズします。
cur.close()

#connectionオブジェクトをクローズします。
conn.close()

ファイルを保存(ここではsample.pyとしました)し、Anaconda Powershell Promptを起動して作成したソースコードを実行しましょう。

(base) PS C:\Users\User> python .\sample.py
(base) PS C:\Users\User>

成功したら何も表示されずに次のプロンプトが表示されると思います。

エラーの場合は書き間違いが無いか確認してください。
DSN(接続文字列)を確認してみてください。 password はご自身で設定されたパスワードに置き換えてくださいね。

レコードが追加されたことをpsqlで確認しましょう。

sampledb=# select * from step_hist_row;
 id | user_name |      step_date      | step_count
----+-----------+---------------------+------------
  1 | tanupapa  | 2001-10-01 20:38:40 |          0
  2 | tanupapa  | 2001-10-02 20:38:40 |          0
(2 行)

今回insertした内容が追加されたことがわかります。

WEB-APIとして作成してみる

今度はWEB-APIとして動作するよう、Flaskを用いて作ってみます。

動作を簡単な絵にしたものです。

WEB-APIとしては③と④の機能があれば良いのですが、これ単体でテストができるように①と②を追加します。①GETメソッドでアクセスされたときに、テスト用にusername、stepdate、stepcount を入力してPOSTしてくれる②FORMをブラウザに返します。
※WEB-APIでアクセスされるときはPOSTメソッドなのでGETメソッドでアクセスされるのはテスト時に限定される。セキュリティを考えるとなんらか認証した方が良いと思いますがここでは割愛します。

早速ソースコードを書いてみましょう。

import os
from flask import Flask
import psycopg2

DSN= "postgresql://postgres:password@localhost:5432/sampledb"
app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def index():
    try:
        if request.method == "GET":
            return """
            <form action="/" method="POST">
            <input name="username"></input>
            <input name="stepdate"></input>
            <input name="stepcount"></input>
            <input type="submit" value="送信する">
            </form>"""
        else:
            username = str(request.form["username"])        
            stepdate = str(request.form["stepdate"])
            stepcount = str(request.form["stepcount"])

            msg = "username : " + username + ",stepdate : " + stepdate + ",stepcount : " + stepcount
            #with get_connection() as conn:
            with psycopg2.connect(DSN) as conn:
                with conn.cursor() as cur:
                    cur.execute("INSERT INTO step_hist_row(user_name, step_date,step_count) VALUES ((%s), (%s), (%s));", (username,stepdate,stepcount,))
                conn.commit()
            return msg + ",OK"
    except psycopg2.Error as e:
        errmsg = msg + ",PostgreSQL Error: " + e.diag.message_primary
        print(errmsg)
        return errmsg
        
if __name__ == "__main__":
    
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)

app = Flask(name)はappという変数にFlaskのインスタンスを格納しており、これ以降Flaskの機能を利用する際に、app.route(/)のような形で記載します。

nameは Python の特殊なグローバル変数の1つで、Python のプログラムがどこから実行されているかを格納しています。Python のプログラムがコマンドラインから直接呼ばれた場合、 name には main という文字列が格納されます。

@app.route(‘/’, methods=[“GET”, “POST”]) という行は、 / というURLに対応するアクションを登録しています。アクションはその直下に関数として記載します。ここではdef index():がそれにあたります。例えばhttp://localhost/というURLでAPIにアクセスされたら、index()関数が呼ばれることになります。

APIがアクセスされる際のメソッドも指定されています。methods=[“GET”, “POST”]がそれで、この場合はGETとPOSTが許可されています。明示的に指定しない場合GETのみ許可されます。許可されない メソッド でのアクセスの場合エラー応答を返します。

関数の中のtry:~ except psycopg2.Error as e:は、try:~ exceptで囲われた範囲でエラーが発生した場合に、except以下で処理を行う宣言をしています。予期しないエラーであればアプリケーションごと異常終了すべきですが、今回の場合だと、user_name, step_dateで重複した値や不正な値(step_dateに日付以外を入れられるとか)が入れられる可能性があり、APIのアクセス元にエラーが発生したよと伝えて、エラーはアクセス元で処理し、APIは他からのアクセス受付を続行すべきです。

psycopg2.Error as e:はpsycopg2関連のエラー(DB関連のエラー)をここで処理するという宣言です。それ以外のエラーが発生した場合は異常終了となります。

if request.method == “GET”:でGETでアクセスされた際の処理を記述しています。
ここではテスト用にusername、stepdate、stepcount を入力してPOSTしてくれるFormをブラウザに返すようにしています。

そのあとのelse:でPOSTでアクセスされた際の処理を記述しています。

username = str(request.form[“username”])でPOSTで送信されたパラメータusernameの値を変数usernameに格納しています。stepdate、stepcountも同様です。

先程試したサンプルでは、conn = psycopg2.connect(DSN)としてコネクションオブジェクトを取得していましたが、その場合は使い終わったらconn.close()としてコネクションクローズする必要がありました。今回with psycopg2.connect(DSN) as conn:としてwith句を用いることで、with句を抜けたときに勝手にクローズしてくれるので便利(というかソースが見やすくなる)です。

cur.execute(‘INSERT INTO step_hist_row(user_name, step_date,step_count) VALUES ((%s), (%s), (%s));’, (username,stepdate,stepcount,))
→%Sを用いることで後方のタプルで置換してくれます。

if name == “main“:
→Python のプログラムがコマンドラインから直接呼ばれた場合にこの後の処理を行います。
 app.run(host=”0.0.0.0″, port=port)が待ち受け開始のコマンドなので、別ファイルからライブラリとして本ファイルが呼ばれた場合は待ち受けしないことになります。※おそらく別ファイルで待ち受け開始されるでしょう。

port = int(os.getenv(“PORT”, 5000))
待ち受けのポート番号を指定しています。osの環境変数でPORTが設定されていればその値、設定がない場合は5000番を設定します。

ファイルを保存(ここではmain.pyとしました)して、 Anaconda Powershell Promptを起動して作成したソースコードを実行しましょう。

(base) PS C:\Users\User> python .\main.py
 * Serving Flask app "api_sample" (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: off
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) で待ち受け開始したことがわかります。

ブラウザを立ち上げて、http:localhost:5000/にアクセスしてみてください。

簡単なFormが表示されたと思います。
値を入力して送信するをクリックしてください。

ブラウザ上、入力した値とOKが表示されたら成功です。

psqlで実際に値が登録されたことを確認しましょう。

sampledb=# select * from step_hist_row;
 id | user_name |      step_date      | step_count
----+-----------+---------------------+------------
  1 | tanupapa  | 2001-10-01 20:38:40 |          0
  2 | tanupapa  | 2001-10-02 20:38:40 |          0
  3 | tanupapa  | 2021-10-09 00:00:00 |          5
(3 行)

正常動作が確認できたので、次回はHeroku上にデプロイして確認してみます。

コメント

タイトルとURLをコピーしました