BEARで始めるWebアプリケーション開発 その11「リソースをWebAPIとして外部に公開する」

今回は、リソースをWebAPI*1として外部に公開する為の方法について学びます。

リソースをWebAPIとして提供する場合、外部からはGETのみで、かつ返す表現がXMLJSONの場合は非常に簡単で、PageのonOutputハンドラでdisplayメソッドを使っていたところを、outputメソッドに変えるだけです。

<?php
    public function onOutput()
    {
        $this->output('xml');
        //$this->output('json');
    }
?>

BEARでは、リソースが値を返す時点では、表現を伴わない単なるデータ構造になっているので*2、状況に応じた表現の変更を極めて容易に行う事ができます。

この、表現形式を決めるアウトプットフィルタは自分で作る事もできて、"App/Resource/output"というディレクトリを作って、その中に"{形式名}.php"というファイル名でPHPファイルを作成すると、それを利用する事ができるようになります。

デフォルトで用意されているアウトプットフィルタは、PEARディレクトリ配下の"BEAR/Resource/output"の中にあります。デフォルトのアウトプットフィルタの動作を変えたい場合は、ここから"App/Resource/output"にコピーしてきて中身を書き換えてやれば、そちらが優先して使われるようになります。

今回は試しに、何らかの画像生成を行ってIMAGICKオブジェクトを返すリソースを作った時に、それを画像ファイルとしてHTTP出力するアウトプットフィルタを作ってみました。

<?php
/**
 * イメージ出力
 *
 * @param array $values  出力データ
 * @param array $options オプション(type:gif|jpeg|jpg|png , expire:有効期限)
 *
 * @return BEAR_Ro
 */
function outputImage($values, array $options)
{
    $ro = BEAR::factory('BEAR_Ro');
    $type = ( isset($options['type']) === true ) ? $options['type'] : 'png';
    switch ( $type ) {
        case 'gif':
            $mime = 'image/gif';
            break;
        case 'jpeg':
        case 'jpg':
            $mime = 'image/jpeg';
            break;
        case 'png':
            $mime = 'image/png';
            break;
    }
    $expire = ( isset($options['expire']) === true && $options['expire'] > 0 )
        ? $options['expire'] : 0;
    $headers = array();
    $headers['X-BEAR-Output: IMAGE'] = 'Content-Type: '.$mime;
    $headers[] = 'Expires: '.$expire;
    $headers[] = 'Last-Modified: '.gmdate('D, d M Y H:i:s ', time()).' GMT';
    $headers[] = 'Cache-Control: public';
    $headers[] = 'Pragma: ';
    $ro->setHeaders($headers);
    $ro->setBody(array_shift($values));
    return $ro;
}
?>

これを、"App/Resource/output/image.php"として作成しておいて、Pageファイルのアウトプットフィルタを以下のようにすると画像データを返すようになるので、imgタグのsrcとかで使えるようになります。

<?php
    public function onOutput()
    {
        $this->output('image', array('type' => 'png'));
    }
?>

今回は、リソース側で画像生成するような場合の想定でしたが、「リソース自体は普通に連想配列を返すけど、出力する時にその情報を利用して画像生成してHTTP出力する」*3なんていうアウトプットフィルタも簡単に作れる事が分かるかと思います。

次回は?

今回は実は元々、外部からリソースのCRUD操作を行えるような、RESTfulWebAPI用Page作成にしようと思っていたんですが、現状、PUTやDELETEも含めた外部向けWebAPIを作る予定は無かったし、むしろアウトプットフィルタの方が使いどころが多いかなと思って、アウトプットフィルタの話にしました。

次回の内容はまだ決めていないのですが、イベント駆動の辺りかAjaxか、そんな辺りの話にしようと思います。

*1:予告では"RESTfulWebサービス"という言い方をしましたが、"Webを支える技術"での使い分けに倣って、"WebAPI"としました。

*2:"リソース自体は表現を決めない"という特徴がある故に、リソース自体で考えると対人用とか対機械用とかの区別が無いモノと言えるので、"Webを支える技術"で言うところの「WebサービスとWeb APIを分けて考えない」という事を実現できているのではないかと思います。

*3:具体例で言うと、はてブAPIみたいな感じで、リソースは数値データだけを返すようにしておいて、アウトプットフィルタで画像生成するようにするイメージ。