參考:https://tech.meituan.com/koa-restql.htmlhtml
在現代的業務系統中,後端開發工做基本上能夠被拆分爲三項:數據庫
本文將介紹如何利用 RestQL 來很是有效地減小「數據操做」相關的工做量。npm
咱們先來作個假設。後端
60 * 4 = 240
個API。40 * 20 * 4 = 3200
個API。因此在上述假設場景中,後端工程師要編寫 3200 + 240 = 3440 個 API。並且這還不是所有,假如後端代碼須要 100% 的測試覆蓋,那麼工程師們就要寫至少 3440 個測試!數組
60 張表 = 3440 個 API + 3440 個單元測試app
衆所周知,數據操做 API 的實現過程基本上是重複的,有的同窗甚至認爲這是低端的,體現不出工程師價值的工做,純粹的「體力活」。可是卻沒有一個能真正解放生產力的方案。koa
儘管咱們把數據庫抽象成了「關係型」數據庫,把操做數據的命令抽象成了 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())
在使用sequelize
定義關聯時,咱們能夠設定restql
參數,實現訪問控制。例如:
禁止經過restql
訪問關聯:
models.user.hasOne(
models.privacy,
{
restql: {
ignore: true } } )
禁止經過restql
使用指定的 HTTP 方法訪問關聯
models.user.hasOne(
models.privacy,
{
restql: {
ignore: ['get'] } } )