在 LeanCloud 中使用 GraphQL

GraphQL 是 FaceBook 開源的一套數據查詢語言,也是 Relay 欽定的組件,可以在客戶端以一種非常靈活的語法來獲取數據,但目前支持 GraphQL 的服務還比較少,最近 GitHub 也宣布了其開放 API 支持了 GraphQL。

因為 GraphQL 的支持需要伺服器端的更改,因此我選擇了在 LeanCloud 的數據服務的基礎上用 Node.js 編寫一個中間層,運行在雲引擎上,將 GraphQL 的查詢翻譯成對 LeanCloud SDK 的調用,為客戶端提供 GraphQL 支持。

我也參考了其他語言和框架的 GraphQL 支持,它們都需要開發者進行很多的開發或配置工作。這是因為無論在 MySQL 還是 MongoDB 中都並沒有記錄數據之間的關聯關係(Id 和 ObjectId 都不會記錄指向的表或集合,MySQL 的外鍵倒是會記錄,但可惜用戶不多);而且即使你定義了數據之間的關聯,你還是需要去定義許可權 —— 哪些用戶可以訪問哪些數據。

而 LeanCloud 的 Relation 和 Pointer 都記錄了所指向的 Class,同時 LeanCloud 本身也有一套基於 sessionToken 和 ACL 的許可權控制機制,因此我們完全可以做到從 LeanCloud 的數據服務獲取數據之間的管理,然後遵循現有的 ACL 來自動實現對 GraphQL 的支持。

leancloud/leancloud-graphql 就是這樣的一個項目,你只需將它部署到雲引擎上,不需要改動一行代碼,便可以用 GraphQL 查詢你在 LeanCloud 上的所有數據。

相較於 RESTful 和 SQL,GraphQL 為數據定義了嚴格的類型,你可以使用這樣一個靈活的語言將數據通過關係組合起來,所見即所得地得到你想要的數據。得益於 GraphQL 的類型系統,你還可以在調試工具(graphql.leanapp.cn)中得到精確的錯誤提示和補全建議。

例如這裡我們查詢 Todo 這個 Class 中按優先順序排序的前兩條數據,獲取 title、priority,並將 owner 這個 Pointer 展開:

query {n Todo(ascending: priority, limit: 2) {n title, priority, owner {n usernamen }n }n}n

結果:

{n Todo: [{n title: "緊急 Bug 修復",n priority: 0,n owner: {n username: "someone"n }n }, {n title: "打電話給 Peter",n priority: 5,n owner: {n username: "someone"n }n }]n}n

目前 leancloud-graphql 已經實現了 LeanCloud 中大部分的查詢參數和查詢條件,你可以任意地組合這些條件。例如我們可以查詢優先順序大於 5 且存在 content 屬性的數據:

query {n Todo(exists: {content: true}, greaterThan: {priority: 5}) {n title, content, priorityn }n}n

GraphQL 最大的亮點還是對關係查詢的支持,無論是 Relation 還是 Pointer 你都可以任意地展開,而不必受到 LeanCloud RESTful API 只能展開一層的限制。例如我們查詢所有的 TodoFolder 中的 Todo(Relation)並展開 owner(Pointer):

query {n TodoFolder {n name,n containedTodos {n title, owner {n username, emailn }n }n }n}n

結果(省略了一部分):

{n TodoFolder: [{n name: "工作",n containedTodos: [{n title: "緊急 Bug 修復",n owner: {n username: "someone",n email: "test@example.com"n }n }, // ...n ]n }, // ...n ]n}n

你也可以在關係查詢上附加查詢參數或條件。例如我們查詢所有 TodoFolder 中優先順序最高的一個 Todo:

query {n TodoFolder {n name, containedTodos(limit: 1, ascending: priority) {n title, priorityn }n }n}n

結果:

{n TodoFolder: [{n name: "工作",n containedTodos: [n {title: "緊急 Bug 修復", priority: 0}n ]n }, n name: "購物清單",n containedTodos: [n {title: "買酸奶", priority: 10}n ]n }, {n name: "someone",n containedTodos: [n {title: "緊急 Bug 修復", priority: 0}n ]n }]n}n

在實現一對多關係時,我們經常會在「多」上面保存一個到「一」的指針,例如一個 Todo 會有一個叫 owner 的 Pointer 指向用戶表。在這時,leancloud-graphql 會自動在用戶表上添加一個叫 ownerOfTodo 的屬性用來表示這個反向關係,你可以像展開一個 Relation 一樣展開這個反向關係,例如我們查詢每個用戶的 Todo 並展開 title:

query {n _User {n username, ownerOfTodo {n titlen }n }n}n

結果:

{n _User: [{n username: "someone",n ownerOfTodo: [n {title: "緊急 Bug 修復"},n {title: "打電話給 Peter"},n {title: "還信用卡賬單"},n {title: "買酸奶"}n ]n }]n}n

對 leancloud/leancloud-graphql 的簡單介紹就到這裡,更多使用方法和功能介紹可以在項目的 GitHub 主頁上看到,這個項目本身也是開源的。

推薦閱讀:

leancloud用戶系統
LeanCloud 層層加固雲端數據安全性之剖析
如何優雅地修改前同事的混亂代碼?
從 HTTP 0.9 到 QUIC
線程之間傳遞 ThreadLocal 對象

TAG:LeanCloud | 关系数据库 | Nodejs |