CakePHPでJSONを返すAPIを作る

CakePHP

以前、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では酷な話です。
なので最初は受け取る側が何を欲しいか、ということから考えていきます。
用途にもよりますが、基本的に下記が求められていると思います。

  1. APIの実行が上手くいったか(ステータス)
  2. エラーの場合、エラーの種類(エラーコード)
  3. エラーの場合、エラーの理由(エラーメッセージ)
  4. 実行結果(リザルト)

これを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();      
    }
  }
}

という感じで自由自在に処理を切り分けることができますね。

CakePHPWebAPI
スポンサーリンク
この記事が気に入ったら
いいね!しよう
最新情報をお届けします。
この記事を書いた人

スパイスファクトリー株式会社 Webエンジニア。フロントエンドやWebサイトの高速化が得意です。インフラ・バックエンドも一通りやってます。
個人的なお仕事のご依頼や情報交換などはお問い合わせまたはTwitterにメンションをお願いします。

ShoheiTaiをフォローする
このエントリーが役に立ったらシェアをお願いします!
イケてないコード – Webエンジニアのブログ

コメント

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