restlt/restlt

RestLite。一个轻量级的PHP RESTful服务器实现

2.0.11b 2016-02-23 18:42 UTC

README

##PHP中的一个“瘦”RESTful服务器实现 RestLt 是一个灵活的小型库,允许您构建RESTful服务。V2.0.0b支持PHP 5.5及以上版本。欢迎任何反馈!

构建状态 ##安装 ###使用Composer 在您的 composer.json 文件的 require 部分添加 RestLt 的信息,如下所示

{ 
        "require" :
        { 
                "restlt/restlt":"2.0.0b"
        }
}

运行 composer.phar --dev update

###使用GIT克隆 使用此 URL 克隆存储库 https://github.com/ivolator/restlt.git

##基础知识 ###服务器端点设置

//Get instance of the server by passing the server base url
$s = new Server ( '/' );
//Tell the server where to find the resources
$s->registerResourceFolder ( SOME_APPLICATION_ROOT .  '/resources', 'name\space\resources' );
$s->registerResourceClass('example\name\space\Resource');
echo $s->serve ();
exit;

在您的基本服务器目录中添加一个 .htaccess 文件,包含以下内容

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

现在您已经初始化了 RestLt。

###创建资源

在 Rest Lite 中,资源是一个扩展 \restlt\Resource 类的类。每个资源可以包含响应多个 GET、POST、PUT、DELETE 和 PATCH 请求的方法。需要注意的是,当您将资源注册到服务器时,您要么注册一个资源文件夹并提供一个命名空间,要么通过提供资源类的 FQNS(完全限定名称空间)提供一个单个资源。提供 FQNS 是必要的。

要配置资源的 URI,您需要设置几个东西。所有元数据都可以通过 PHP 文档块进行配置。以下将展示示例。

  1. 在类的文档块中添加 @resourceBaseUri。这将设置所有包含在此资源中的方法的基础 URI '@resourceBaseUri /user' - 注意前面的正斜杠
  2. 在类方法的文档块中添加 @method。这将告诉服务器该函数将响应哪种 HTTP 方法。例如,@method POST@method GET 将告诉服务器 HTTP 方法是 GET 或 POST
  3. 为方法 URI 添加 @methodUri 值。
    • @methodUri / - 您可以只添加 "/" 或省略注解
    • @methodUri /list - 固定示例
    • @methodUri /user/([0-9]+) - 正则表达式示例 - 总是添加括号 '(' 和 ')' 围绕正则表达式 注意您的资源完整 URI 是服务器基础 URI(在 \restlt\Server 初始化期间设置)和 @resourceBaseUri + @methodUri 的组合。通常将 URI 视为正则表达式。这就是它的评估方式,并遵循 preg_match() 的绑定规则,您用括号括起来的任何内容都将成为您方法的一个参数。

例如,如果您的完整 URI 最终变为 /account/([0-9]+)/contact/([a-z]+),则您的函数应接受两个参数。第一个参数将是数字序列,第二个参数将是字母。

资源可以拥有多个方法,这些方法可以响应 GET、POST 等。

###一个简单的资源示例

namespace restlt\examples\resources;
/**
 * 
 * @resourceBaseUri /resource1
 */
class Resource1 extends \restlt\Resource {
    /**
     * Note that the regex in "()" gets converted to a parameter of the method
     * Since v 1.1.0a this user comment section will appear in a simple HTML format
     * accesible at the root of ther server like this: http://url.com/approot.html
     * @method GET
     * @methodUri /([0-9]+)
     */
    public function getMe($id = '') {
        $obj = new \stdClass ();
        $obj->a = array (9,8,7);
        //obtain the "someParam" - from POST or GET
        $this->get ( 'someParam',$defaultValueIfParamIsMissing );
        return $boj;
    }
    /**
     *
     * @method PUT
     * @methodUri /save
     */
    public function putMe() {
        //fetch the parameters from the query string
        $params = $this->request->getQueryParams ();
        $params = $this->request->getPostParams ();
        
        //get the raw data
        $postPayload= $this->request->getRawPost ();
            ......
        //return whatever you want
        return $res;
    }
}

对于刚刚编写的资源,我们创建了两种方法,Resource1::getMe()Resource1::putMe()。这些方法没有命名规范,名称的选择是为了提高清晰度。方法Resource1::get()将响应'GET' HTTP方法,访问它的URI为/resource1/123或任何符合正则表达式的数字。后者URI将附加到服务器基本URI上。您在实例化\restlt\Server时设置服务器基本URI。

与'GET'类似,我们构建了'PUT'方法Resource1::putMy()。当服务器收到'PUT'请求且URI为/resource1/save时,Resource1::putMe()方法将返回您决定返回的内容。为了在客户端以XML或JSON格式字符串的形式接收数据,方法必须返回数据。JSON或XML转换是自动完成的。关于如何在高级部分添加您自己的输出风格的更多讨论将在后面进行。

访问资源方法中的GET、POST和原始数据。

//accessing GET
        $params = $this->request->getQueryParams ();
//accessing POST
        $params = $this->request->getPostParams ();

获取作为提交到主体中的原始数据

        $postPayload= $this->request->getRawPost (); 

一次获取一个参数

        $this->getRequest()->get($paramName, $default);
        also available through a local method call
        $this->get($paramName, $default);

获取参数($_REQUEST)的同时提供默认值。这有助于您避免对已设置或空值的检查

        $this->get('page',1);

###公共API文档 如果您为API资源方法添加了用户注释,现在可以通过访问服务器的/baseUri/introspect.html URI来访问它们。http://myserveurl.com/serverroot/introspect.html其中serverroot是您在初始化\restlt\Server对象时定义的基本URI。

##错误处理 ###异常 服务器抛出的所有异常最终都会变成404或500错误。如果您抛出自己的错误,结果代码将为500,但您有控制权来决定抛出或捕获的内容。后者生成的信息将作为结果的一部分发送到服务器作为错误对象。例如,如果您抛出throw new \Exception('My Error',1000);,您将在响应体中得到以下内容。然而,HTTP状态代码将是500。

<?xml version="1.0" encoding="UTF-8"?>
<result>
  <errors>
    <error>
      <error>
        <message>My Error</message>
        <code>1000</code>
      </error>
    </error>
  </errors>
</result>

###PHP/user错误 由E_ERROR、E_USER_ERROR、E_WARNING、E_USER_WARNING、E_CORE_ERROR、E_CORE_WARNING、E_DEPRECATED和E_STRICT引起的错误将变成500。您可以在PHP错误日志中看到这个错误。

一些高级用法

事件钩子

假设您需要向执行流程添加一些变化或执行检查、记录或其他想法。有三个事件钩子提供了这样做的方法。这些事件钩子提供的回调必须是Callable。以下是方法或函数签名。

在“Before”事件 - *在流程进入您的资源方法之前.*

class Resource1 extends \restlt\Resource {
    public function __construct() {
        $f1 = function ($r) {
             //do something
        };
        $this->on ( Resource::ON_BEFORE, 'myFunctionName', $f1 );
    }

或者,而不是闭包,传递Callable

    $this->on ( Resource::ON_BEFORE, 'myFunctionName', array($obj,$method) );
    }

为此事件提供的回调函数具有以下签名

    /**
     * ON_BEFORE callbakc
     * @param \restlt\Resource $resource 
     * @return void
     * /
    $f = function (\restlt\Resource $resource){};

在“After”事件 - *资源函数返回之后.*

$this->on ( Resource::ON_AFTER, 'myFunctionName', array($obj,$method) );
* The callback function provided for this event has the following signature *
    /**
     * ON_AFTER call back
     * @param \restlt\Resource $resource 
     * @param mixed $return the result of your resource method
     * @return void
     * /
    $f = function (\restlt\Resource $resource, $return){};

在“错误”时 - *当方法内部发生错误时.*

如果在方法内部抛出异常,它最终会被顶层捕获,并且您将得到500。实际上,此事件在E_ERROR、E_USER_ERROR、E_WARNING、E_USER_WARNING、E_CORE_ERROR、E_CORE_WARNING、E_DEPRECATED、E_STRICT被抛出时触发。

    $this->on ( Resource::ON_ERROR, 'myFunctionName', array($obj,$method) );

遵循回调函数签名

/**
 * ON_ERROR call back
 * @param \restlt\Resource $resource 
 * @return \Exception $exception - the result of your resource method
 * @return void
 * /
$f = function (\restlt\Resource $resource, \Exception $exception){};

注册事件示例

为特定资源方法注册ON_BEFORE事件钩子

        $f1 = function ($r) {
        //do something
        };
        //the context here is the Resource, hence $this
        $this->on (\restlt\Resource::ON_BEFORE, 'getMe', $f1 );

为任何资源方法注册ON_BEFORE事件钩子

        $f1 = function ($r) {
        //do something
        };
        //the context here is the Resource, hence $this
        $this->on (\restlt\Resource::ON_BEFORE, NULL, $f1 );

添加一些缓存

由于添加大量资源可能会影响性能,RestLt 使用了一些缓存来减轻这个问题。在其最基本实现中,服务器原生支持 Memcached 扩展。然而,有方法可以添加已经支持多种后端缓存适配器的第三方缓存系统。为了使用 RestLt 支持的任何一种第三方实现,您应通过 Composer 安装它们。当您通过 Composer 安装 RestLt 时,您应该看到了有关这些的建议。

使用内置的 Memcached 实现

    $memcached = new Memcached ();
    $memcached->addServer ( 'localhost', 11211 );
    $s = new Server ( '/' );
    $s->setCacheAdapter ( new \restlt\cache\RestltMemcachedAdapter( $memcached ) );
    $s->serve ();

使用 Zend 缓存组件 - [Zend Cache] (http://framework.zend.com/manual/2.0/en/modules/zend.cache.storage.adapter.html)

如果您已经使用 ZF2 缓存组件,那么将它们添加到 RestLt 中有一个简单的方法。这里假设您知道如何使用 Zend\Cache\StorageFactory::adapterFactory,您需要获取一个存储适配器。

    $zendCache = Zend\Cache\StorageFactory::adapterFactory('apc',$options);
    $s->setCacheAdapter ( new \restlt\cache\ZFCacheAdapter ( $zendCache ) );

使用 Doctrine 的缓存实现 - Doctrine Cache

Here you should know how to obtain a Doctrine CacheProvider.
    $memcache = new Memcache();
    $memcache->connect('memcache_host', 11211);
    $doctrineCacheProvider = new \Doctrine\Common\Cache\MemcacheCache();
    $doctrineCacheProvider->setMemcache($memcache);
    $s->setCacheAdapter ( new \restlt\cache\DoctrineCacheAdapter($doctrineCacheProvider) );

添加您喜欢的缓存实现

如果您不使用前面提到的任何一种由 Zend 或 Doctrine 提供的缓存实现,您可以添加自己的。为了使我们能够使用第三方缓存库,我们需要创建一个实现了 restlt\cache\CacheAdapterInterface 的类。

class OtherframeworkCacheAdapter implements CacheAdapterInterface {
        public function __construct($cacheInstance = null) {
                // 
        }
        public function test($key) {
                //
        }

        public function set($key, $item) {
                //
        }

        public function get($key) {
                //
        }
}

现在您必须在您的引导程序中告诉服务器使用它。

$s->setCacheAdapter ( new \restlt\cache\OtherfameworkCacheAdapter($otherframeworkInstance) );

##为资源方法或资源类添加自己的注解 如果您需要在请求执行期间锁定一些所需的数据,您可以在方法中添加一个自定义注解。以下是如何使用该功能的示例。

/**
 * @method POST
 * @baseUri /save
 * @allowedRoles admin, mega-admin
 */
 public function saveUser(){
     $roles = $this->annotations->get('allowedRoles');
     //do something here with the data. $roles now has the string 'admin, mega-admin'
     return $something;
 }

需要自定义输出吗?

默认情况下,RestLt 附带了 json 和 xml 输出策略。假设您需要提供一些自定义的加密或加密响应。无论原因是什么,您可能有一天会这样做。这可能是因为您想通过某种特定协议与客户端通信,并想将其数据包装在它里面。或者可能想更改当前的输出。下面是如何做。###添加自定义响应。首先,我们需要创建一个实现了 \restlt\output\TypeConversionStrategyInterface 的类。让我们开始。

namespace my\name\space;
class SerializeOutputStrategy implements \restlt\output\TypeConversionStrategyInterface {
    /**
     * @see \restlt\output\TypeConversionStrategyInterface::execute()
     */
    public function execute(\restlt\Result $data) {
        return serialize($data);
    }
}

就这样。我们已经为 RestLt 服务器实现了序列化输出策略。接下来要做的就是告诉服务器。

$s->getResponse()->addResponseOutputStrategies('sphp', '\my\name\space\SerializeOutputStrategy');

我们在这里做了以下事情。我们让服务器知道,如果我们遇到 URL 中的 '.sphp' 扩展名,我们将使用关联的输出响应,在这种情况下是 SerializeOutputStrategy。现在,所有具有类似以下 URL 的请求(GET、POST、PUT、PATCH 等)都将根据您的新输出策略返回序列化数据:

  • http://example.com/my/path/123.sphp
  • http://example.com/my/path.sphp?q=stuff

等等。

###扩展当前可用的 \restlt\output\XmlTypeConverter\restlt\output\JsonTypeConverter。要修改当前 JSON 或 XML 转换器的行为,您需要扩展它们。这里没有太多要记住的。扩展类与扩展任何其他类没有区别。然而,您需要将您的新类注册到服务器上,并将其与 XML 或 JSON 类型相关联。

$s->getResponse()->addResponseOutputStrategies('xml', '\my\name\space\MyXmlStrategy');

现在,所有具有类似以下 URL 的请求(例如 http://example.com/my/path.xml?q=stuff)都将由您的新类处理。同样,使用 'Content-type:application/xml' 发起的客户端请求也将由它处理。如果您决定扩展 JSON 转换器,这也适用。

##文档块元数据引用

资源类文档块

@resourceBaseUri -> specifies the resource base URI relative to the Server base URI

资源方法文档块

@method -> specifies what HTTP method this resource method respnds to. POST, GET, PUT, PATCH, DELETE are allowed
@methodUri -> URI relative to the resource base uri value specified in the @resourceBaseUri
@cacheControlMaxAge -> this value directly affects the 'Cache-Control max-age' HTTP header value and has nothing to do with the local caching feature  

日志记录

从版本1.2.0-alpha开始,可以通过以下方式添加记录器。新增了兼容PSR-3的记录器。但是,并没有添加本地的记录器实现,可能也不会添加。您需要注入自己的记录器,该记录器应该实现Psr\Log\LoggerInterface接口。

$server->setLog($yourcustomLogger);

在此版本发布时,将添加对Zend Logger的适配器。

其他使用技巧

强制服务器始终以指定的响应类型响应,而不管请求的Content-type是什么

默认行为由Accept头部指定。如果Accept是plain/text或任何不指向SML或JSON的内容,则默认响应将以JSON返回。

  1. 强制所有注册的资源始终以XML或JSON响应
$s = new \restlt\Server('base/uri');
$s->getResponse()->setForceResponseType(Response::APPLICATION_JSON);
  1. 强制方法始终以XML或JSON响应
/**
 * @resourceBaseUri /entity
 */
class myResource extends \restlt\Resource
/**
 * @methodUri /submit
 * @method POST
 */
public function myMethod(){
    $this->getResponse()->setForceResponseType(\restlt\Response::APPLICATION_XML);
    #some code here ...
    return $result;
}
  1. 非编码技巧,强制期望的响应:当为客户端创建URL时,只需将.json或.xml追加到URI的末尾(不是查询部分)。