以前、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();
}
}
}という感じで自由自在に処理を切り分けることができますね。


コメント