Jsonql——給RESTful API插上一對翅膀


  RESTful API是目前比較成熟的一套互聯網應用程序的API設計理論,規范了服務端資源的定義及訪問。我們團隊服務端就采用了RESTful。

  可是在現實開發過程中,還是有些問題。

  客戶端在獲取資源的時候,可能不同地方需要資源的不同的屬性,而服務端常常會把幾乎所有屬性全部返回,這在App上會造成一些流量的浪費,譬如我要加載一個普通的產品列表,需要產品圖片、產品名稱、價格、庫存等屬性,而另一個瀏覽歷史可能只需要名稱和價格,這總不能寫兩個API吧?或者說附帶一個請求參數告訴服務端要返回哪些屬性,這倒行得通,可很不優雅。

  重要的是客戶端還會有一個界面可能需要調用多個不同類型的資源的情況,最經典的就是電商App,個人中心界面里,既需要用戶的一些信息,又要查詢收藏數量、關注數量、足跡數量,又要查詢不同狀態下的訂單數量,或者下方還有推薦商品列表。客戶端一個界面請求多個資源URI會降低客戶端的體驗自然不好,或者需要服務端需要額外提供適配客戶端的API能解決,可一旦界面有變化這些接口也要重新做適配。

  這些問題不是很重要,可問題多了,客戶端開發和服務端開發要掐架。

  有沒有相對好的解決辦法呢?

  本人不才,搞了個 Jsonql(https://github.com/liyanjie8712/Jsonql,意圖給RESTful按上一對翅膀。

  Jsonql是什么,咱給它起了個高大上的名字,Jsonql = Responsive Json Query Language,響應式Json查詢語言,客戶端要什么樣的數據,由客戶端來決定。服務端只提供資源及支持的查詢函數,客戶端編寫查詢請求,服務端解析並組裝數據返回給客戶端。這下服務端一勞永逸,客戶端界面及數據綁定隨便折騰去吧,挖哈哈~

  先來看看Jsonql的語法:

  變量的定義:$變量名

  變量必須先定義后使用,所有在定義前的引用都是錯誤的。
  變量具有作用域,只在當前定義它的 “{}” 及嵌套的子 “{}” 內有效,同時子作用域會覆蓋父作用域定義的同名變量。

  例:$abc。

  資源的引用:資源名[]

  資源名必須與服務端公開的資源列表中的名稱一致並區分大小寫。

  例:users[]。

  方法的調用:.方法名(參數)

  例:.where(age>=18).count()。

  字段的訪問:.字段名

  例:.user.name。

  資源的枚舉:=>$

  使用資源訪問符 “=>” 對資源進行枚舉,“=>” 左側定義資源的引用,右側定義資源的輸出(類似javascript對象)。
  如果右側定義以 “[]” 結尾,則表示遍歷資源輸出一個數組,否則表示只輸出索引為0的元素。
  “$” 表示對資源中元素的引用。
  定義輸出時,輸出字段與元素字段名稱一致時,可以省略 “$.”。

  例:users[] => { uuid:$.id, name, age }

  使用表達式:{{表達式}}

  使用表達式可以執行一些運算操作,包括四則運算、邏輯運算、位運算等。 表達式必須使用“{{}}”包括,其運算結果為一個值。 表達式中可以使用變量,可以訪問屬性,但不可使用資源,不可調用方法。

  例:{{ 1 + 2 - 3 * 4 / 5 % 6 }}、{{ $abc > 0 }}、{{ true ? 1 : 0 }}

  寫個查詢的Demo,就拿用戶與訂單來:

 1 {
 2     //獲取用戶信息
 3     user: users[].where(id==1) =>
 4     {
 5         uuid: $.id,                             //ID
 6         username,                               //用戶名
 7         avatar,                                 //頭像
 8         account:
 9         {
10             coins: $.account.coins,
11             points: $.account.points
12         }
13     },
14     //定義一個訂單資源的變量
15     $orders: orders[].where(user.id==1),
16     //訂單不同狀態下的數量
17     orderCount:
18     { 
19         created: $orders.count(status==1),
20         payed: $orders.count(status==2),
21         delivered: $orders.count(status==3),
22         completed: $orders.count(status==4)
23     },
24     //后去該用戶的訂單列表,前10條數據
25     orders: $orders.orderBy(createTime).skip(0).take(10) =>
26     {
27         uuid: $.id,                             //ID
28         serial,                                 //訂單號
29         status                                  //訂單狀態
30     }[]
31 }

  將要返回什么數據呢?來看看:

 1 {
 2     "user": {
 3         "uuid": 1,
 4         "username": "abcdefg",
 5         "avatar": "http://img.xxxx.com/avatars/1.jpg",
 6         "account": {
 7             "coins": 8888,
 8             "points": 9999
 9         }
10     },
11     "ordercount": { 
12         "created": 0,
13         "payed": 2,
14         "delivered": 1,
15         "completed": 18
16     },
17     "orders": [
18         {
19             "uuid": 1,
20             "serial": "00001",
21             "status": 2,
22         },
23         {
24             "uuid": 2,
25             "serial": "00002",
26             "status": 2,
27         },
28         //…………
29     ]
30 }

  查什么返回什么,是不是方便多了?並且支持Linq Method,搞C#的童鞋是不是很眼熟?當然還支持動態表達式計算,譬如:

1 {
2     $abc: 1,
3     $def: 2,
4     result: {{$abc + $def + 3}}  
5 }

  返回結果:

1 {
2     "result": 6
3 }

  Jsonql只是為了讓查詢更好用,資源的增刪改操作還交給RESTful吧。

  就到這里。目前Jsonql支持AspNet與AspNetCore,GitHub里帶有簡單的Demo,有興趣的童鞋可以下載下來玩一玩,相應的依賴包已發布到:http://myget.org/gallery/liyanjie。

  覺得不錯就給顆星吧,另外歡迎大牛指導一二,不勝感激。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM