RestQL:現代化的 API 開發方式

youbin1129 8年前發布 | 11K 次閱讀 API RestQL

koa-restql 已經在 github 開源并在 npm 發布。感興趣的同學可以前往圍觀一下。歡迎 Pull Request,同時熱烈歡迎 Star。

在現代的業務系統中,后端開發工作基本上可以被拆分為三項:

  • 接口鑒權 。例如拍段是不是當前系統的用戶,以及該用戶是否有權限訪問接口。
  • 與其他系統的交互 。例如調用第三方的服務,或內部搭建的其他服務。
  • 數據操作 。基本上所有需要持久化存儲的系統都會在這項工作上耗費大量時間。

本文將介紹如何利用 RestQL 來非常有效地減少「數據操作」相關的工作量。

現狀與挑戰

我們先來做個假設。

  • 假設系統中有 60 張表,每張表對應的接口都要有四種 CRUD 的 API。那么就需要后端工程師寫 60 * 4 = 240 個API。
  • 假設上述 60 張表中,40 張表存的是資源類的數據,其余 20 張表為關系類的數據,也就是說每張表和 20 張表都要進行關聯,每個關聯也需要四種 CRUD 操作,那么又要增加 40 * 20 * 4 = 3200 個API。

所以在上述假設場景中,后端工程師要編寫 3200 + 240 = 3440 個 API。而且這還不是全部。假如后端代碼需要 100% 的測試覆蓋,那么工程師們就要寫至少 3440 個測試!

60 張表 = 3440 個 API + 3440 + 個單元測試

眾所周知,數據操作 API 的實現過程基本上是重復的,有的同學甚至認為這是低端的,體現不出工程師價值的工作,純粹的「體力活」。但是卻沒有一個能真正解放生產力的方案。

解決思路

盡管我們把數據庫抽象成了「關系型」數據庫,把操作數據的命令抽象成了 SQL ,同時我們也有了 MySQL 客戶端,甚至是 sequelize 這種非常方便的庫,也有「RESTful」API 命名規則,但是接口的實現從來都是需要工程師們自己用手敲出來的。

如果說我看得比別人遠,那是因為我站在巨人的肩膀上。

所以我們在現有的技術基礎上再抽象,把已有的東西重新組合起來,拼裝成一個新的工具,幫助工程師從「體力活」中解脫出來,解放生產力。

什么樣的工具

最開始的時候,我們最先需要明確的問題就是:「我們需要什么樣的工具?」或者說「這種工具要幫我們解決什么問題?」。

實際上我們從剛才的假設中,已經可以得出結論:我們希望有一個工具可以讓工程師免于編寫數據操作 API, 把數據庫操作直接映射到 HTTP RESTful API 上

調用方式

如何請求

為了解釋「如何請求」,我們先從一些公認的規則出發,舉一個例子,然后再從例子中抽象出一些規則。

注意:為了更便于理解,我們把所有的命名從客戶端一直穿透到數據庫,所以請不要糾結于我們在定義一個 API 時名詞單復數的問題。

基本用例

幾乎所有的系統都會有一個用戶表(user)。根據 RESTful 規則的約定,我們應該把訪問 user 表的 API 路徑定義為 /user ,并把 CRUD 的訪問方法映射到 HTTP 協議中的四種方法: GET 、 POST 、 PUT 、 DELETE 。

比如:

  • GET /user :獲取用戶列表,應該返回一個數組。
  • GET /user/:id :獲取指定的用戶,應該返回一個對象。
  • POST /user :創建一個用戶,應該返回被存儲的對象,狀態碼應該為 201(Created)。
  • PUT /user :修改一個用戶的信息,應該返回修改后的對象。
  • DELETE /user/:id :刪除一個用戶,狀態碼應該為 204(No Content)。

如果 user 表有一個關系表 feed,那么我們的路徑就會再復雜一點:

  • GET /user/:id/feed 或 GET /feed?user_id=:id :獲取某個用戶的帖子,應該返回一個數組。
  • GET /user/:id/feed/:feed_id 或 GET /feed/:id :獲取指定的帖子,應該返回一個對象。

上述的例子中還會衍生出其他的數據操作,不僅僅只有 GET ,這里不一一列舉了。

抽象出規則

上一節中,列舉了要提供一個表的數據訪問 API,大概要實現哪些路由。從這些枚舉中,可以找出其中的規律,總結出一套規則。最終我們在「 把能實現的路由,全部實現 」的原則基礎上,開發了 RestQL 的 koa 版本。

支持的 HTTP 方法:

HTTP verb CRUD
GET Read  
POST Create  
PUT Create/Update  
DELETE Delete  

支持的帶有 body 的 HTTP 方法:

HTTP verb List Single
POST Array/Object ×  
PUT Array/Object Object  

說明:

  • List 路徑為返回值為數組的路徑,包括:
    • /resource
    • /resource/:id/association , association 為 1:n 關系
    • /resource/:id/association , association 為 n:m 關系
  • Single 路徑為返回值為單個對象的路徑,包括:
    • /resource/:id
    • /resource/:id/association , association 為 1:1 關系
    • /resource/:id/association/:id , association 為 1:n 關系
    • /resource/:id/association/:id , association 為 n:m 關系

如何使用

我們已經開源了 koa-restql,koa 應用開發者可以通過 npm 安裝它:

npm install koa-restql

然后在 koa 應用的代碼中引用 RestQL:

const koa       = require('koa')
const RestQL    = require('koa-restql')

let app = koa()
// Build APIs from `sequelize.models`
let restql = new RestQL(sequelize.models)
app.use(restql.routes())

常見問題

修改參數

用戶可以通過 querystring 來修改參數。強烈建議使用 qs 對 querystring 進行解析,例如:

qs.stringify({a: 1, b:2}) // => a=1&b=2

RestQL 中的 querystring 僅有 3 條規則:

  • 所有不以 _ 開頭的建,都會被放進 sequelize#query() 的 where 參數中。例如:

    // query
     {
       name: "Li Xin"
     }
     // option for sequelize
     {
       where: {
         name: "Li Xin"
       }
     }
  • 所有以 _ 開頭的建,都會被放進 sequelize#query() 的參數中,和 where 保持平級。例如:

    // query
      {
        _limit: 10
      }
      // option for sequelize
      {
        limit: 10
      }
  • 當需要使用關系時,可以用關系名稱的字符串代替關系對象傳入。例如需要使用 include 時:

    // query
      {
        _include: ['friends']
      }
      // option for sequelize
      {
        include: [
          models.user.association.friends
        ]
      }

訪問控制

通常來說,我們有兩種方法實現訪問控制:

通過中間件

在 koa 應用掛載 RestQL 的 router 之前,可以實現一個鑒權中間件,控制用戶的訪問權限:

app.use(authorizeMiddleware)
app.use(restql.routes())

通過 restql 參數

在使用 sequelize 定義關聯時,我們可以設定 restql 參數,實現訪問控制。例如:

  • 禁止通過 restql 訪問關聯:

    models.user.hasOne(
        models.privacy,
        {
          restql: {
            ignore: true
          }
        }
      )
  • 禁止通過 restql 使用指定的 HTTP 方法訪問關聯

    models.user.hasOne(
        models.privacy,
        {
          restql: {
            ignore: ['get']
          }
        }
      )

其他語言/框架

目前我們僅實現了基于 node 和 koa 的版本,還沒有其他語言/框架的實現版本。歡迎開發者提交其他語言/框架的實現到 RestQL 組

參考鏈接

 

來自:http://tech.meituan.com/koa-restql.html

 

 本文由用戶 youbin1129 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!