安装并启用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
模组文件结构
1custom_restfulapi/
2├─ src/
3│ ├─ Plugin/
4│ │ ├─ resource/
5│ │ │ ├─ entity/
6│ │ │ │ ├─ Testentity__1_0.php
7├─ custom_restfulapi.info
8├─ custom_restfulapi.module
API RESOURCES要放在src/Plugin下。 *.info 和 *.module 的内容跟其他自定义模组的相差无几,方法一样,此处从略。
1name = RESTful custom
2description = Custom RESTful resource.
3core = 7.x
4dependencies[] = restful
5
6registry_autoload[] = PSR-4
建立API端点(API endpoint)
此处以建立暴露entity的API端点为例,一般地,在Plugin/resource
里创建entity文件夹(非必须),然后新建一个PHP文件Testentity__1_0.php
,文件内容大致如下:
1<?php
2
3namespace Drupal\custom_restfulapi\Plugin\resource\entity;
4
5use Drupal\restful\Plugin\resource\ResourceEntity;
6use Drupal\restful\Plugin\resource\ResourceInterface;
7
8/**
9 * Class Testentity__1_0
10 * @package Drupal\custom_restfulapi\Plugin\resource\entity
11 *
12 * @Resource(
13 * name = "Testentity:1.0",
14 * description = "A simple testapi.",
15 * resource = "testentity",
16 * label = "Test entity ",
17 * authenticationTypes = {
18 * "token"
19 * },
20 * authenticationOptional = TRUE,
21 * dataProvider = {
22 * "entityType": "sampleentitytype",
23 * "bundles": {
24 * "samplebundle","samplebundle2"
25 * },
26 * },
27 * majorVersion = 1,
28 * minorVersion = 0
29 * )
30 */
31
32class Testentity__1_0 extends ResourceEntity implements ResourceInterface
33{
34 /**
35 * Overrides ResourceEntity::publicFields().
36 * @return array
37 */
38 protected function publicFields()
39 {
40 $public_fields = parent::publicFields();
41 $public_fields['customfieldname'] = array(
42 'property'=>'field_number',
43 'process_callbacks' => array(
44 array($this,'toFloat'),
45 ),
46 );
47 return $public_fields;
48 }
49
50 /**
51 * @param $value
52 * @return float
53 */
54 public function toFloat($value){
55 $value = (float)$value;
56 return $value;
57 }
58
59}
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
1{
2 "access_token": "D8uD2xjDtlT8ym0BiM-n4R-cssRACxgf34xsBQpgGKw",
3 "type": "Bearer",
4 "expires_in": 86400,
5 "refresh_token": "jhHpCr3FubMsSyE-9B6wPgtPMeQn2u34-P4blDSiXrw"
6}
authenticationOptional
若值为TRUE则不验证,直接可以获取资源,这个设置在开发和测试的时候很好用;dataProvider
定义了数据来源,具体到了bundle,可以多个bundle;majorVersion
和minorVersion
定义了版本号。
在类 Class Testentity__1_0 中,我们使用 publicFields() 定义输出json中的entity各字段的key和value值,默认输出id
,label
和self
字段,如果不需要暴露可以在return $public_fields
前unset
它们,比如这样:
1 unset($public_fields['self'],$public_fields['label']);
2 $public_fields['id']['methods']=array();
可以对每个字段值格式化,过滤等进行处理,添加一个回调函数即可,比如本例中的:
1'process_callbacks'=> array(
2 array($this,'toFloat'),
3 ),
返回的json范例
1{
2 "data": [
3 {
4 "id":1,
5 "label":"The Beatles",
6 "self":"http:\/\/example.com\/api\/v0.1\/testentity\/1",
7 "customfieldname":"19.22"
8 },
9 {
10 "id":2,
11 "label":"Chuck Berry",
12 "self":"http:\/\/example.com\/api\/v0.1\/testentity\/2",
13 "customfieldname":"19.55"
14 }
15 ],
16 "count":2,
17 "self":{
18 "title":"Self",
19 "href":"http:\/\/example.com\/api\/v0.1\/testentity"
20 }
21}
自定义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类改写为:
1class Testentity__1_0 extends ResourceEntity implements ResourceInterface {
2 /**
3 * Override ResourceEntity::controllersInfo()
4 * @return array
5 */
6 public function controllersInfo()
7 {
8 return array('^.*$' => array(
9 RequestInterface::METHOD_GET => 'customviewEntity',
10 ));
11 }
12
13 public function customviewEntity($sid){
14 $input = $this->request->getParsedInput();
15 $query = $this->getDataProvider()->EFQObject();
16 if(!empty($input)){
17 $start_time = $input['start'];
18 $end_time = $input['end'];
19 $result = $query -> entityCondition('entity_type','sampleentitytype')
20 ->entityCondition('bundle','samplebundle')
21 ->propertyCondition('person_id',$sid)
22 ->propertyCondition('created',array($start_time,$end_time),'BETWEEN')
23 ->execute();
24 }else{
25 $result = $query -> entityCondition('entity_type','sampleentitytype')
26 ->entityCondition('bundle','samplebundle')
27 ->propertyCondition('person_id',$sid)
28 ->execute();
29 }
30 $jsonarray = array();
31 $sum = 0;
32 if(!empty($result)){
33 $e = entity_load('sampleentitytype',array_keys($result['sampleentitytype']));
34 foreach ($e as $entity) {
35 $sum += $entity->field_fp['und']['0']['value'];
36 }
37 $jsonarray = array('psersonid'=>$sid,'sum'=>$sum);
38 }
39 return $jsonarray;
40 }
41}
这样就能通过 http://example.com/testentity/$id?start=$starttime&end=$endtime
这样的URL来通过一段时间来过滤内容了,并且默认传$id的位置还能被定义成其他非数字字符,自由度很高。
小结
Restful 模组确实上手有点困难,相关内容杂七杂八并且重复性较高,多数时候还是只能直接读module的代码来去看它怎么用。另外1.x版本和2.x版本相也是很大的,要小心….
更多详情请参考 官方wiki 文档