CakePHPでWEB APIを自作してみる。
2013/06/14
サーバAで運営しているDBのデータを、サーバBで必要になりました。
サーバAのデータをエクスポートしてサーバBへインポートし、作成したプログラムで必要に応じて取得する、という流れでもいいのですが、エクスポート、インポートする手間が惜しい。
ならば、サーバBからのリクエストに対し必要なデータを送信するという、いわゆる API をサーバAに設置してはどうかという流れになり、調べてみましたら、意外と簡単にできることが判明。
忘備録代わりにコチラに作り方をポストしてみます。
通信仕様の決定
バージョンは例によって1.3です。
例として『メールアドレスをキーに顧客データを取得する』といったものを作成してみたいと思います。
APIの中身は、以前使ったことがある amazon の API を真似て作ってみます。
アマゾンAPIにリクエスト方式を見ると、オプションを「?」及び「&」で繋げる GETメソッドで HTTP通信を行なっています。
いわゆる、REST(Representational State Transfer の略)という仕様ですね。
リクエスト方式としてはあと、SOAP(Simple Object Access Protocol)という方式がありますが、こちらは、XMLを使って引数やオプションを指定します。
ということで、今回はアマゾンに倣って REST を使ってみることとします。
送信側PHP
では、まずはGETメソッドをHTTP経由でAPIプログラムに投げる処理から。
単純に書くと、以下の様な手順になります。
- 送信するパラメータを準備
- パラメータを&で連結
- URLを作成
- APIで生成されたXMLを、file_get_contents関数で受け取る
- 手順4で受信した返り値(XML)を、 simplexml_load_string関数 で、オブジェクトに代入
- CakePHPのCakePHPのxmlパーサで、配列に変換する
これを、PHPで書くとこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
// APIのURL $apiURL = 'http://sample-api-url.com/api'; // トークン作成 $token = sha1(uniqid(mt_rand(), true)); // パラメータ準備 $params = array( 'email' => 'someone@mailaddress.com', // 検索するメールアドレス 'accesskey' => 'abc0123-toogie-wataamefrog', 'token' => $token, 'timestamp' => date("Y-m-d\TH:i:s\Z"), ); // Keyでソート ksort($params); // パラメータを連結 $string = ''; foreach ( $params AS $k => $v ) { $string .= '&' . rawurlencode($k) . '=' . rawurlencode($v); } // 先頭の「&」を省く $string = substr($string, 1); // URL を作成 $apiOptions = $apiURL .'?' . $string; $apiResult = file_get_contents($apiOptions); // XMLオブジェクト作成 $sResult = simplexml_load_string($apiResult); // CakePHPのxmlパーサを利用 uses('Xml'); $xml = new XML($sResult); $xml_array = Set::reverse($xml); // debug pr($xml_array) // 欲しい処理 if ( $xml_array['SimpleXMLElement']['Item']['status'] == 'true' ) { // 受け取った結果を使った処理 //(省略) } |
XMLで返ってきたものを、CakePHPのXMLパーサを利用して、配列に変換しています。
これで foreach でもなんでも使えるようになります。
API側のPHPプログラム
呼ばれる先のPHP。コチラはCakePHPではなく、プレーンなPHPです。
GETで送信されているので、$_GET でパラメータを取得し、欲しい内容作成し XML形式で出力しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
// アカウント部分を取得 $email = explode('@', $_GET['email']); $email_account = $email[0]; // ドメイン名取得 $email_domain_name = $email[1]; // アカウント名、ドメイン名からDBを検索 // 存在する場合は、 $ret_email にメールアドレスを、存在しない場合は返り値は false とする処理 //(省略) // APIの戻り値を作成 if ( $ret_email == false ) { // 失敗パラメータ作成 $returns = array( 'result' => array( 'status' => 'false', 'timestamp' => $_GET['timestamp'], 'token' => $_GET['token'], 'email' => 'null', ), ); } else { // 成功パラメータ作成 $returns = array( 'result' => array( 'status' => 'true', 'timestamp' => $_GET['timestamp'], 'token' => $_GET['token'], 'email' => $ret_email, ), ); } // XMLのルートタグとXML宣言 $xmlStr = '<?xml version="1.0" encoding="UTF-8" ?><root></root>'; // オブジェクトの生成 $xmlObj = new SimpleXMLElement($xmlStr); // パラメータ配列を使ってXMLに要素を追加していく foreach( $returns as $arr ){ $xmlitem = $xml->addChild("item"); // itemタグ追加 if ( is_array($arr) ) { foreach ( $arr as $key => $value ){ $xmlitem->addChild($key, $value); // 子要素を追加 } } } // XMLを出力 header('Access-Control-Allow-Origin:*'); header("Content-Type: text/xml"); echo $xmlObj->asXML(); |
パラメータには検索するメールアドレスの他、認証用やセキュリティ対策用のオプションを指定して、できるだけ固いシステムにすることが必要かと思われます。
今回のサンプルでは、timestamp と token はGETで受けたものをそのまま返しているだけです。
帰ってくる結果
pr($xml_array);
した結果。
1 2 3 4 5 6 7 8 9 10 11 |
Array( [SimpleXMLElement] => Array ( [Item] => Array( [status] => true [timestamp] => 2013-06-05T13:15:57Z [token] => 6093766c33b27d08dbad4462dfc500e3ba1b5fc3 [email] => someone@mailaddress.com ) ) ); |
意外と簡単にできることが分かり、色々と画策中。
先にも書きましたが、セキュリティ面を強固にする必要があると思うので、その辺りをまた研究したいと思います。
[tgAmazonItemLookup asin="B005UK3K8O" related="1"]