python – WebAPIを作ってjsonでやりとりして、ローカルからサーバ上のDBにアクセスする

python 3.X系です

レンタルサーバを使っていて、ローカルのプログラムからレンタルサーバ上のDBにアクセスしたいな~
なんてことはあんまりないかもしれませんが、ローカルからDBサーバのアドレス、ポートに
直接アクセスは出来ないのが普通だと思います

今回はWebAPIをphpで用意してやって、jsonでローカルとサーバのやりとりをすることで、
DBサーバと間接的にやりとりするプログラムを作る機会があったので私がやった方法をメモしておきます

 

仕組みの概要

仕組みはざっと↓な感じです

001_diagram

① SQL文作成(python)

pythonのプログラム上で、DBサーバで実行するためのSQLを記述します

 

② SQL文をjsonにしてPOSTリクエスト投げる(python)

SQL文をjson形式に変換して、httpのPOSTリクエストをレンタルサーバ上のphpに投げます

 

③ json受け取り(php)

php側でリクエストを受けたら、jsonを受け取って、SQL文を変数に格納します

 

④ SQL発行(php)

SQL文を普通にMySQLに投げます

 

⑤ 結果受け取って、jsonにして返す(php)

DBから結果が返ってきたら、またjsonにしてローカル側に返します

 

⑥ 結果をjsonで受け取って、配列に格納(python)

httpレスポンスを受けて、またまたjsonを取り出して、プログラムコード中で使いたいように配列にぶち込みます

 

では、サンプルコードを交えつつ、解説していきます
 

python側のサンプルコード

まずpython(ローカル)側です、
ちなみに私が使用しているレンタルサーバではhttpのbasic認証でパスワードをかけていたので、認証前提のコードになっています

import urllib.request
import json

# basic認証用の関数
def setup_basic_auth(base_uri, user, password):
    password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
    password_mgr.add_password(
        realm=None,
        uri=base_uri,
        user=user,
        passwd=password)
    auth_handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
    opener = urllib.request.build_opener(auth_handler)
    urllib.request.install_opener(opener)


if __name__ == '__main__':
    # 認証の定義
    url = 'phpのURL'
    user = 'ユーザ'
    passwd = 'パスワード'

    # httpをPOSTで投げる
    method = 'POST'

    # jsonを送るのでMIME設定
    headers = {"Content-Type": "application/json"}

    # 実行したいsqlを変数に格納
    sql_txt = "SELCT * FROM `test_table`"

    # jsonのオブジェクトを作ってutf-8にする
    obj = {"query": sql_txt}
    json_data = json.dumps(obj).encode("utf-8")

    # basic認証を通す
    setup_basic_auth(url, user, passwd)

    # phpにPOSTリクエスト投げる
    req = urllib.request.Request(url=url, data=json_data, method=method, headers=headers)

    # レスポンスを受け取って、jsonを変換しつつ配列に突っ込む
    response = urllib.request.urlopen(req)
    json_str = response.read().decode('utf-8')
    db_result = json.loads(json_str)

こんな感じです、
jsonを送るので、MIMEタイプを教えてあげるのと、
受け取る時に、json.loads()を使って、リスト(or 辞書)に変換してやるところがポイントでしょうか

では続いて、php側のサンプルコードです
 

php側のサンプルコード

MySQLにクエリ投げるところは今回のポイントじゃないので、省略しちゃいます

//jsonデータの受け取り、jsonをデコードしてオブジェクトに格納
$json_string = file_get_contents('php://input');
$obj = json_decode($json_string);

//エラーが発生したとき用の配列とフラグ
$return_msg_abnormal = array();
$error_flg = "";

//jsonが受け取れなかったら、エラーフラグと、エラーメッセージを入れる
if(!isset($obj)){
    $return_msg_abnormal[]["error"] = "GET NG";
    $error_flg = "ABNORMAL";
}

//オブジェクトからSQLを取り出す
//python側ではSQL文のテキストをqueryというキーで送っていたので
//以下の通りように取り出します
$sql = $obj->query;

/*
 * DB接続うんぬんかんぬんは省略します
 */

//エラーフラグが設定されてなかったらSQL実行
$select_result = array();
if(empty($error_flg)){
    $result = mysql_query($sql);
    if (!$result) {
        $return_msg_abnormal[]["error"] = "check sql!";
        $error_flg = "ABNORMAL";
    } else {
        while ($row = mysql_fetch_assoc($result)) {
            $select_result[] = $row;
        }
    }
}

//jsonで返すのでヘッダーにMIMEタイプの定義
header('Content-Type: application/json');

//エラーが発生してなかったらSQLの実行結果を返す、エラーだったらメッセージを返す
if(!empty($error_flg)){
    echo json_encode($return_msg_abnormal, JSON_PRETTY_PRINT);
}else{
    echo json_encode($select_result, JSON_PRETTY_PRINT);
}

いかがでしょうか

わりと雑な感じで申し訳ないですが、こんな感じでWebAPIを通せば、レンタルサーバでもhttp経由でDBサーバとやりとりできるので、もしそういう要件があれば参考にしていただければと思います!

2 件のコメント

  1. ガエタノジェントリーマグナム 返信

    なんとすばらしい☆*:.。. o(≧▽≦)o .。.:*☆

  2. mobkin 投稿者返信

    ありがとうございます!以前の職場でも要件がありましたが、顧客が自分のDBのデータを好きなように取って加工したい、みたいな要望がありました。これであれば、DMZなんかで内部ネットワークにアクセスさせないようにしていても、http経由で実現できますね。データ量とかが絡んでくると色々考慮しなければいけませんが・・

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です