[任務]
用筋斗雲框架創建一個Web接口項目叫mysvc,創建數據庫,提供對ApiLog對象的操作接口。
先從github上下載開源的筋斗雲後端框架及示例應用:https://github.com/skyshore2001/jdcloud-php
建議安裝git工具直接下載,便於以後更新,例如直接創建Web接口項目叫mysvc:
git clone https://github.com/skyshore2001/jdcloud-php.git mysvc
如果github訪問困難,也可以用這個git倉庫: http://dacatec.com/git/jdcloud-php.git
配置好Web服務器,php環境和MySQL數據庫。
注意PHP最低版本需要5.4版本,需要打開mysql, pdo, gd等支持。
在Web服務器上將項目下的接口主目錄(即server目錄)暴露出來,假設URL是:
http://localhost/mysvc/
先別急着訪問這個地址,而是先配置數據庫連接等,在瀏覽器中打開這個頁面:
http://localhost/mysvc/tool/init.php
這個工具會先檢查運行環境是否正確,如有異常(比如php版本不對,缺少組件等)請先解決。
然後創建接口應用使用的數據庫和配置文件。
初始化工具運行完後,生成的配置文件爲php/conf.user.php
,之後也可以手工編輯該文件。
數據模型定義在主設計文檔DESIGN.wiki中,作爲示例,裏面定義了一些數據模型,像用戶(User),訂單(Ordr)以及前面提過的操作日誌(ApiLog)等,還定義了一些常用接口,如登錄操作(login)等。
我們通過通過命令行工具tool/upgrade.php可以創建或更新數據庫:
cd tool
php upgrade.php
(這時進入upgrade交互操作,輸入initdb命令創建或更新數據庫)
> initdb
(輸入命令q退出)
> q
我們進入server目錄看看:
- api.php就是接口應用程序,提供Web接口。
- tool目錄中是一些線上工具,比如查看日誌、計劃任務等。
- 對象型接口一般寫在文件php/api_objects.php中,函數型接口一般寫在php/api_functions.php中。
裏面已經包含了一些示例接口,一般在示例基礎上修改即可。 - 共用邏輯寫在app.php中,各種工具和接口應用程序均可用;注意如果只是多個接口共用的邏輯,直接寫在api.php文件中就可以。
爲了學習對象型接口,我們將php/api_objects.php清空,從頭開始來寫,以暴露ApiLog對象爲例,在php/api_objects.php中加上一句:
class AC_ApiLog extends AccessControl
{
}
這一句代碼就提供了對ApiLog對象的標準增刪改查(CRUD)接口如下:
查詢對象列表,支持分頁、查詢條件、統計等:
ApiLog.query() -> table(id, tm, addr)
添加對象,通過POST參數傳遞字段值,返回新對象的id
ApiLog.add()(tm, addr) -> id
獲取對象
ApiLog.get(id) -> {id, tm, addr}
更新對象,通過POST參數傳遞字段值。
ApiLog.set(id)(tm?, addr?)
刪除對象
ApiLog.del(id)
[接口原型的描述方式]
在上面的接口原型描述中,用了兩個括號的比如add/set操作,表示第一個括號中的參數通過GET參數(也叫URL參數)傳遞,第二個括號中的參數用POST參數(也叫FORM參數)傳遞。
多數接口參數支持用GET方式或POST方式傳遞,除非在接口說明中特別指定。
帶”?”表示參數或返回的屬性是可選項,可以不存在。
接口原型中只描述調用成功時返回數據的數據結構,完整的返回格式是[0, 返回數據]
;而在調用失敗時,統一返回[非0錯誤碼, 錯誤信息]
。
我們可以直接用curl工具來模擬前端調用,用add接口添加一行數據,使用HTTP POST請求:
curl http://localhost/mysvc/api.php/ApiLog.add -d "tm=2016-9-9 10:10" -d "addr=shanghai"
curl用”-d”參數指定參數通過HTTP body來傳遞,由於默認使用HTTP POST謂詞和form格式(Content-Type=application/x-www-form-urlencoded),
這種參數一般稱爲POST參數或FORM參數,與通過URL傳遞的GET參數相區別。
結果輸出一個JSON數組:
[0,11338]
0表示調用成功,後面是成功時返回的數據,add操作返回對象id,可供get/set/del操作使用。
用get接口取出這個對象出來看看:
curl http://localhost/mysvc/api.php/ApiLog.get?id=11338
輸出:
[0,{"id":11338,"tm":"2016-09-09 00:00:00","addr":"shanghai"}]
這裏參數id是通過URL傳遞的。
前面說過,未顯式說明時,接口的參數可以通過URL或POST參數方式來傳遞,所以本例中URL參數id也可以通過POST參數來傳遞:
curl http://localhost/mysvc/api.php/ApiLog.get -d "id=11338"
如果取一個不存在的對象,會得到錯誤碼和錯誤信息,比如:
curl http://localhost/mysvc/api.php/ApiLog.get?id=999999
輸出:
[1,"參數不正確"]
再用set接口做一個更新,按接口要求,要將id參數放在URL中,要更新的字段及值用POST參數:
curl http://localhost/mysvc/api.php/ApiLog.set?id=11338 -d "addr=beijing"
輸出:
[0, "OK"]
再看很靈活的query接口,取下列表,默認支持分頁,會輸出一個nextkey字段:
curl http://localhost/mysvc/api.php/ApiLog.query
返回示例:
[0,{
"h":["id","tm","addr"],
"d":[[11353,"2016-01-04 18:31:06","::1"],[11352,"2016-02-04 18:30:43","::1"],...],
"nextkey":11349
}]
返回的格式稱爲壓縮表,”h”爲表頭字段,”d”爲表的數據,在接口描述中用table(id, 其它字段...)
表示。
默認返回的JSON數據未經美化,效率較高,如果想看的清楚些,可以在配置文件conf.user.php中設置測試模式:
putenv("P_TEST_MODE=1");
測試模式不僅美化輸出數據,還可返回更多調試信息,前端可用URL參數_debug
設置調試等級0-9,如果設置爲9,甚至可以查看SQL調用日誌:
curl http://localhost/mysvc/api.php/ApiLog.query?_debug=9
這在調試SQL語句時很有用。此外,測試模式還會開放某些內部接口,以及缺省允許跨域訪問,便於通過web頁面測試接口。注意線上生產環境絕不可設置爲測試模式。
query接口也支持常用的數組返回,需要加上_fmt=list
參數:
curl http://localhost/mysvc/api.php/ApiLog.query -d "_fmt=list"
返回示例:
[0,{
"list": [
{ "id": 11353, "tm": "2016-01-04 18:31:06", "addr": "::1" },
{ "id": 11352, "tm": "2016-02-04 18:30:43", "addr": "::1" },
...
],
"nextkey":11349
}]
還可以將_fmt
參數指定爲”csv”, “excel”, “txt”等,在瀏覽器訪問時可直接下載相應格式的文件,讀者可自己嘗試。
取下一頁可以用_pagekey字段,還可指定一次取的數據條數,用_pagesz字段:
curl "http://localhost/mysvc/api.php/ApiLog.query?_pagekey=11349&_pagesz=5"
不僅支持分頁,query接口非常靈活,可以指定返回字段、查詢條件、排序方式,
比如查詢2016年1月份的數據(cond參數),結果只需返回id, addr字段(res參數,也可用於get接口),按id倒序排列(orderby參數):
curl http://localhost/mysvc/api.php/ApiLog.query -d "res=id,addr" -d "cond=tm>='2016-1-1' and tm<'2016-2-1'" -d "orderby=id desc"
甚至可以做統計,比如查看2016年1月裏,列出訪問次數排名前10的地址,以及每個地址訪問了多少次服務器,也可以通過query接口直接查出。
做一個按addr字段的分組統計(gres參數):
curl http://localhost/mysvc/api.php/ApiLog.query -d "gres=addr" -d "res=count(*) cnt" -d "cond=tm>='2016-1-1' and tm<'2016-2-1'" -d "orderby=cnt desc" -d "_pagesz=10"
輸出示例:
[0,{
"h":["addr","cnt"],
"d":[["140.206.255.50",1],["101.44.63.119",73],["121.42.0.85",70],...],
"nextkey": 3
}]
[接口調用的描述方式]
在之後的示例中,我們將使用接口原型來描述一個調用,不再使用curl,比如上面的調用將表示成:
ApiLog.query(gres=addr
res="count(*) cnt"
cond="tm>'2016-1-1' and tm<'2016-2-1'"
orderby="cnt desc"
_pagesz=10
)
->
{
"h":["addr","cnt"],
"d":[["140.206.255.50",1],["101.44.63.119",73],["121.42.0.85",70],...],
"nextkey": 3
}
返回數據如非特別聲明,我們將只討論調用成功時返回的部分,比如說返回”OK”實際上表示返回[0, "OK"]
。