tohokuaikiのチラシの裏

技術的ネタとか。

PHPでRESTサーバを実装するライブラリLuracast/Restler

PHPでRESTサーバを書きたくなった場合、F.Wならそれの下地はあるだろうけどそれ程でも…っていう場合など。

Luracast/Restler

日本語の記事は見つからなかったけど、このライブラリが鉄板っぽいので使ってみる。

https://github.com/Luracast/Restler

以下、下記の記事を参考にする。

https://github.com/Luracast/Restler/blob/master/README.md

インストール

composer.pharのあるディレクトリで下記のコマンドを実行。

$php composer.phar create-project luracast/restler {projectName}

で{projectName}のディレクトリができて、その中にインストールされる。

illuminate/viewがバージョンで蹴られた。。。

PHP5.3というのバージョンのせいで蹴られる。Restler自体はこの記事時点で5.3.2あればOKなんだけど。

reated project in example_rest Loading composer repositories with package information Installing dependencies (including require-dev) Your requirements could not be resolved to an installable set of packages.

Problem 1 - illuminate/view v4.2.9 requires php >=5.4.0 -> your PHP version (5.3.3) or "config.platform.php" value does not satisfy that requirement. .... << などと言われる。ので、

    "require":{
        "php":">=5.3.0"
    },
    "require-dev":{
        "luracast/explorer":"*",
        "guzzle/guzzle":"~3.1.1",
        "behat/behat":"2.5.*@stable",
        "rodneyrehm/plist":"dev-master",
        "zendframework/zendamf":"dev-master",
        "symfony/yaml":"*",
        "mustache/mustache": "dev-master",
        "twig/twig": "v1.13.0",
        "illuminate/view": "4.2.*",
        "bshaffer/oauth2-server-php":"v1.0"
    },

とあるのを

    "provide":{
        "illuminate/view": "4.2.*",
    }
    "require":{
        "php":">=5.3.0"
    },
    "require-dev":{
        "luracast/explorer":"*",
        "guzzle/guzzle":"~3.1.1",
        "behat/behat":"2.5.*@stable",
        "rodneyrehm/plist":"dev-master",
        "zendframework/zendamf":"dev-master",
        "symfony/yaml":"*",
        "mustache/mustache": "dev-master",
        "twig/twig": "v1.13.0",
        "bshaffer/oauth2-server-php":"v1.0"
    },

としてとりあえず回避。

サンプル&テスト

インストールディレクトリ内に、publicフォルダがあるのでそれをDocumentRoot配下にシンボリックリンク

http://example.com/public/examples/index.html

http://example.com/public/tests/param/explorer/index.html

http://example.com/public/tests/request_data/explorer/index.html

がサンプル&テストとして使えるようになる。

後はだいたいこれ見ればわかるでしょう・・・・という感じで。

とりあえずベースとして
<?php
require_once 'vendor/restler.php';
use Luracast\Restler\Restler;

$r = new Restler();
$r->addAPIClass('Example'); // repeat for more
$r->handle();

で、ここに後はaddAPIClassでどんどんと加えていく。

クラスの定義を2段階にしたいと思って

index.php

<?php
$r->addAPIClass('foo\Example2'); // repeat for more

foo/Example2.php

<?php
namespace foo;

class Example2{
    function hello($to = "World", $from = "Me"){
        return "Hello $to! From $from ?";
    }
}

とすると、

http://example.com/rest/example2/hello

が使える。

GETメソッド

クラスの各メソッドにHTTPメソッドのプレフィクスを付けるのが決まり。ただ、GETメソッドは省略できる。

エントリポイントのClass/functionで実行されるのが決まる。

引数は、引数名がそのまま使われる。

http://example.com/rest/example/hello?to=hoge&from=adam

を受けたかったら、

<?php
class Example{
    function hello($to = "World", $from = "Me"){
        return "Hello $to! From $from ?";
    }
}

とする。

POSTメソッド

クラスの各メソッドにHTTPメソッドのプレフィクスを付けるのが決まり。なので、postIndexメソッドを作るとそれが使われる。 上記の定義のまま

$ curl -X POST http://example.com/rest/example/hello

ってやると、

{
  "error": {
    "code": 405,
    "message": "Method Not Allowed"
  },
  "debug": {
    "source": "Routes.php:431 at route stage",
    "stages": {
      "success": [
        "get"
      ],
      "failure": [
        "route",
        "negotiate",
        "message"
      ]
    }
  }
}

ってなるので、POSTに対応させるにはpostメソッドを作る。

<?php
class Example{
    function post($to = "World", $from = "Me"){
        return "POST to $to! from $from ?";    
    }

これで

$ curl -X POST http://example.com/rest/example/ -H "Content-Type: application/json" -d '{"to": "ITOH", "from": "Smith"}'
"POST to ITOH! from Smith ?"

と返ってくる。

XMLで返す。

$r = new Restler();
$r->setSupportedFormats('XmlFormat');

ってやると http://example.com/rest/example/hello.xml

とコールすることでXMLで返せるみたい。

みたいというのは、テスト環境でVIEWまわりを扱う"illuminate/view"がうまくインストールできてないからです。

エラーハンドリング

エラーが起こった際には、RestExceptionを投げる。

<?php
throw new RestException(HTTPステータスコード, "エラーメッセージ");

エラーメッセージは省略可能。 HTTPステータスコードは500でいいんじゃないでしょうか。

デバッグモード

最初のインスタンスを作る際、コンストラクタの第一引数をtrueにするとデバッグ情報が抑えられる。

なので、実運用上では

$r = new Restler(true);

とすること。