Drupal7 中Restful模组应用简单介绍
更多详情请参考 官方wiki 文档
安装并启用Restful Module
- Restful 2.x 下载
- drush 安装
drush dl restful
,drush en restful
自定义RESTFUL API模组
- 可参考restful里的范例
sites/all/modules/restful/modules/restful_example
或者测试文件内容sites/all/modules/restful/tests
模组文件结构
custom_restfulapi/
custom_restfulapi/custom_restfulapi.info
custom_restfulapi/custom_restfulapi.module
custom_restfulapi/src/
custom_restfulapi/src/Plugin/
custom_restfulapi/src/Plugin/resource/
custom_restfulapi/src/Plugin/resource/entity/
custom_restfulapi/src/Plugin/resource/entity/Testentity__1_0.php
...
API RESOURCES要放在src/Plugin下。 *.info 和 *.module 的内容跟其他自定义模组的相差无几,方法一样,此处从略。
name = RESTful custom
description = Custom RESTful resource.
core = 7.x
dependencies[] = restful
registry_autoload[] = PSR-4
建立API端点(API endpoint)
此处以建立暴露entity的API端点为例,一般地,在Plugin/resource
里创建entity文件夹(非必须),然后新建一个PHP文件Testentity__1_0.php
,文件内容大致如下:
<?php
namespace Drupal\custom_restfulapi\Plugin\resource\entity;
use Drupal\restful\Plugin\resource\ResourceEntity;
use Drupal\restful\Plugin\resource\ResourceInterface;
/**
* Class Testentity__1_0
* @package Drupal\custom_restfulapi\Plugin\resource\entity
*
* @Resource(
* name = "Testentity:1.0",
* description = "A simple testapi.",
* resource = "testentity",
* label = "Test entity ",
* authenticationTypes = {
* "token"
* },
* authenticationOptional = TRUE,
* dataProvider = {
* "entityType": "sampleentitytype",
* "bundles": {
* "samplebundle","samplebundle2"
* },
* },
* majorVersion = 1,
* minorVersion = 0
* )
*/
class Testentity__1_0 extends ResourceEntity implements ResourceInterface
{
/**
* Overrides ResourceEntity::publicFields().
* @return array
*/
protected function publicFields()
{
$public_fields = parent::publicFields();
$public_fields['customfieldname'] = array(
'property'=>'field_number',
'process_callbacks' => array(
array($this,'toFloat'),
),
);
return $public_fields;
}
/**
* @param $value
* @return float
*/
public function toFloat($value){
$value = (float)$value;
return $value;
}
}
Restful 使用了注释(Annotation)定义资源。
resource=
定义了API接口的URL,比如此处定义的API接口即为example.com\api\testentity
;authenticationTypes
定义验证方式,默认的是HTTP BASIC AUTH,当启用了模组RESTful token authentication
时就可以用本例中的值启用Token authentication。获取token的方法参考这里,简而言之- GET
/api/login-token
- header参数(
Authorization:Basic b2M6b2MxMjM0
),b2M6b2MxMjM0
为“用户名:密码
”BASE64编码后的字符串; - 响应:
- GET
{
"access_token": "D8uD2xjDtlT8ym0BiM-n4R-cssRACxgf34xsBQpgGKw",
"type": "Bearer",
"expires_in": 86400,
"refresh_token": "jhHpCr3FubMsSyE-9B6wPgtPMeQn2u34-P4blDSiXrw"
}
authenticationOptional
若值为TRUE则不验证,直接可以获取资源,这个设置在开发和测试的时候很好用;dataProvider
定义了数据来源,具体到了bundle,可以多个bundle;majorVersion
和minorVersion
定义了版本号。
在类 Class Testentity__1_0 中,我们使用 publicFields() 定义输出json中的entity各字段的key和value值,默认输出id
,label
和self
字段,如果不需要暴露可以在return $public_fields
前unset
它们,比如这样:
...
unset($public_fields['self'],$public_fields['label']);
$public_fields['id']['methods']=array();
可以对每个字段值格式化,过滤等进行处理,添加一个回调函数即可,比如本例中的:
'process_callbacks'=> array(
array($this,'toFloat'),
),
返回的json范例
{
"data": [
{
"id":1,
"label":"The Beatles",
"self":"http:\/\/example.com\/api\/v0.1\/testentity\/1",
"customfieldname":"19.22"
},
{
"id":2,
"label":"Chuck Berry",
"self":"http:\/\/example.com\/api\/v0.1\/testentity\/2",
"customfieldname":"19.55"
}
],
"count":2,
"self":{
"title":"Self",
"href":"http:\/\/example.com\/api\/v0.1\/testentity"
}
}
自定义resource内容
有时候需要返回的json数据并不是单纯的输出entity,可能还需要经过汇总计算等等,这就只能自定义resource内容了。使用 controllersInfo()
函数自定义控制器,然后在自定义function中输出任意array,Restful模组会帮你格式化成相应的json数据包含在data中输出。
Restful的过滤功能个人觉得参数传起来太麻烦了,比如这样子的:https://example.com/api/articles?filter[integer_multiple][value][0]=5&filter[integer_multiple][value][1]=10&filter[integer_multiple][operator][0]=">"&filter[integer_multiple][operator][0]="="
一大长传太恶心了,好在自定义的function中可以直接用 $this->request->getParsedInput()
来获取URL中传入的参数。
一个简单的范例,可以将上面的Testentity__1_0类改写为:
class Testentity__1_0 extends ResourceEntity implements ResourceInterface {
/**
* Override ResourceEntity::controllersInfo()
* @return array
*/
public function controllersInfo()
{
return array('^.*$' => array(
RequestInterface::METHOD_GET => 'customviewEntity',
));
}
public function customviewEntity($sid){
$input = $this->request->getParsedInput();
$query = $this->getDataProvider()->EFQObject();
if(!empty($input)){
$start_time = $input['start'];
$end_time = $input['end'];
$result = $query -> entityCondition('entity_type','sampleentitytype')
->entityCondition('bundle','samplebundle')
->propertyCondition('person_id',$sid)
->propertyCondition('created',array($start_time,$end_time),'BETWEEN')
->execute();
}else{
$result = $query -> entityCondition('entity_type','sampleentitytype')
->entityCondition('bundle','samplebundle')
->propertyCondition('person_id',$sid)
->execute();
}
$jsonarray = array();
$sum = 0;
if(!empty($result)){
$e = entity_load('sampleentitytype',array_keys($result['sampleentitytype']));
foreach ($e as $entity) {
$sum += $entity->field_fp['und']['0']['value'];
}
$jsonarray = array('psersonid'=>$sid,'sum'=>$sum);
}
return $jsonarray;
}
}
这样就能通过 http://example.com/testentity/$id?start=$starttime&end=$endtime
这样的URL来通过一段时间来过滤内容了,并且默认传$id的位置还能被定义成其他非数字字符,自由度很高。
小结
Restful 模组确实上手有点困难,相关内容杂七杂八并且重复性较高,多数时候还是只能直接读module的代码来去看它怎么用。另外1.x版本和2.x版本相也是很大的,要小心....