以前、CakePHPでjQueryのAjaxを使う方法というエントリーを書きましたが、
今回はJSON形式の配列を返却するAPIを作ってみます。
ここ一年間、APIを設計したり使ったりしましたが、自分なりのノウハウをまとめてみようと思います。
JSON形式で返すメリット- javascriptでオブジェクトとしてそのまま扱える
- PHPから他の言語へデータの受け渡しが容易
- JSONはXMLなどと比べ軽量
JSONを返すWebAPIはjavascriptとの相性も良く,Ajaxでのやりとりにも使えます。
PHPの場合はjson_encode、json_decodeで等でJSONと配列を簡単に変換できます。
$json = json_encode(array('あ', 'い', 'う')); echo $json; // ["\u3042","\u3044","\u3046"] ※["あ","い","う"]と同義 $arr = json_decode($json); print_r($arr); // Array ( [0] => あ [1] => い [2] => う )
APIから返すJSONの設計
API設計で考えるべきなのが、JSONを受け取る側が綺麗なコードを書けるようにしてやるか。
複雑な配列形式にしてしまえば受け側もJSONを解析するのが困難になります。
特にフロントエンドで無駄を減らしたいjavascriptでは酷な話です。
なので最初は受け取る側が何を欲しいか、ということから考えていきます。
用途にもよりますが、基本的に下記が求められていると思います。
- APIの実行が上手くいったか(ステータス)
- エラーの場合、エラーの種類(エラーコード)
- エラーの場合、エラーの理由(エラーメッセージ)
- 実行結果(リザルト)
これをPHPで書いていくと
// 成功時 $status = true; $result = array('id' => 100, 'name' => '太郎'); $data = compact('status', 'result'); // 失敗時 $status = false; $result = null; $error = array( 'code' => 404, 'message' => 'データが見つかりません' ); $data = compact('status', 'result', 'error');
こんな感じになりますね。
compactは定義済みの変数を拾って配列にまとめてくれます。
その動作の中で、定義されていない変数は無視してくれるという点が非常に便利。
では、こんな感じの書き方で実際にJSONを返すCakePHPのアクションを作ってみましょう。
CakePHPでJSONを返すAPIを作ろう
まずはControllerから作ります。
class AjaxController extends AppController { // テスト用モデル public $uses = array('User'); public function testApi() { // 今回はJSONのみを返すためViewのレンダーを無効化 $this->autoRender = false; // Ajax以外の通信の場合 if(!$this->request->is('ajax')) { throw new BadRequestException(); } /* ここでDBアクセスなど何かの処理をする */ $result = $this->User->find('list'); // 値が入っているかを確認。 // 値によっては(bool)でキャストしてしまうのも可 $status = !empty($result); if(!$status) { $error = array( 'message' => 'データがありません', 'code' => 404 ); } // JSON形式で返却。errorが定義されていない場合はstatusとresultの配列になる。 return json_encode(compact('status', 'result', 'error')); } }
これで後はjQueryのAjaxからアクセスする。
$(function(){ $('.ajaxBtn').bind('click', function() { $.ajax({ 'type': 'get', 'dataType': 'json', 'url': 'http://localhost/Ajax/testApi/', 'success': function(data) { var list = null; if(data.status) { // 成功時の処理。無事Userからリストを取得する。 list = data.result; } else { // 失敗時の処理。失敗したことを伝える。 alert(data.message); } }, 'error': function() { // アクション側でExceptionが投げられた場合はここに来る。 // エラーをここで処理したい場合はExceptionを投げても良い } }); }); });
JSON形式で返ってくるので、.(ドット)記法で書けちゃいます。
data.resultで取っちゃってください。
CakePHPのアクション側でstatusがfalseになっていても通信は成功しているので
Ajaxのコールバックはsuccessになります。
このsuccessの中で処理を分岐するのに$statusと$error[‘code’]で判定します。
エラーはエラー。errorのコールバックで処理したい!という時はアクション側で例外を投げてやると
errorのコールバックで処理を行うことができます。
class AjaxController extends AppController { // テスト用モデル public $uses = array('User'); public function testApi() { // Ajax以外の通信の場合 if(!$this->request->is('ajax')) { throw new BadRequestException(); } /* ここでDBアクセスなど何かの処理をする */ $result = $this->User->find('list'); $status = !empty($result); if(!$status) { // 例外で落とす throw new NotFoundException(); } } }
という感じで自由自在に処理を切り分けることができますね。
コメント