目前我已經寫了一年多 graphql,也時常思考和 Rest API 的不一樣,以及對 API Design 的啓發。javascript
他山之石能夠攻玉。qraphql 一些自然的設計或者思想對寫 Rest API 有很大的借鑑或參考意義。html
這裏總結下一些受啓發的 API 設計規範。前端
若是你對 graphql 不熟悉,能夠先參考 graphql 中文文檔java
本文連接 shanyue.tech/post/api-de…node
在 graphql 中,scalar 類型 ID
用來表示資源的全局惟一性。在 apollo-client
中也建議客戶端每次請求都把 id 帶上。git
在響應中帶上 id 至少有兩個好處github
query TODO {
todo (id: 10) {
id
name
status
}
}
複製代碼
如客戶端只須要顯示某個 TODO 的狀態以及名稱,則只須要返回 name 以及 status 字段,大大減小了網絡的流量。數據庫
另外, graphql server 須要在數據庫層面也對字段作按需加載。不然,graphql server 與 database 之間也會形成無用的數據 IO 與流量浪費。json
獲取 graphql query 所請求的字段,須要手動解析 GraphQLFieldResolveFn 函數的第四個字段 info,並在每個 field 上自定義一個 directive 標註 Graphql Filed 與 Database Field 的關係後端
在 Rest API 中可使用額外字段作按需加載。 如使用 fields 標記返回須要的字段,若無此字段,默認返回資源的所有字段,在中間件中對 fields 作結構化處理
// 請求 Todo:10,而且只須要 id,name,status 三個字符安
'/api/todos/10?fields=id,name,status'
// 請求 Todo:10 所有資源
'/api/todos/10'
複製代碼
這個請求表示一個用戶列表,每一個用戶須要展現最後一個 Todo 的名稱。Todo 須要使用嵌套對象來表示。
query USERS {
users {
id
name
lastTodo {
id
name
}
}
}
複製代碼
在 Rest API 設計中常常見到全部數據進行了展開,不只沒法定位資源,也很差擴展數據。嵌套數據能夠很靈活的擴展數據,另外也能夠對嵌套數據進行按需加載
const res0 = {
users: [{
id: 1,
name: "山月",
todoName: "學習"
}]
}
// 修改後
const todoFields = {}
const res = {
users: [{
id: 1,
name: "山月",
todo: {
id: 1,
name: "學習",
...fields
}
}]
}
// 能夠這樣設計 API
const api = '/api/users?fields=id,name,todo.id,todo.name'
複製代碼
在 graphql 中,雖沒有一個 scalar 類型來表示時間戳,不過能夠自定義 scalar DateTime 來表示時間。關於時間的格式
參考 StackOverflow 上的問題 the-right-json-date-format
const date = new Date()
// 從 toJSON 的輸出就知道先後端交互須要使用什麼格式了
date.toJSON()
// 2019-03-14T07:41:08.500Z
date.toISOString()
// 2019-03-14T07:41:08.500Z
複製代碼
這樣返回的格式不只符合規範,並且可讀性也比較好。
我見過API中返回的時間戳表示爲 unix timestamp,js timestamp, iso8601 三種格式,較爲混亂。統一的數據格式有利於先後端的聯調,不過這也得益於 graphql 的強類型 schema。
在 graphql 中會返回 { data, errors }
的數據結構,能夠在最後結構化錯誤信息爲
{
"code": "InvalidToken",
"message": "Token 失效",
"httpStatus": 401
}
複製代碼
message
爲可讀性的錯誤信息,能夠由前端直接顯示,code
爲調試用,httpStatus
由下一步的中間件捕捉,設置狀態碼。
在結構化錯誤信息後,能夠順帶把錯誤信息發送到報警系統 (如 Sentry)。不過須要分清 WARN 與 ERROR,如 401,403 應當作 WARN 處理。
恩,好吧。graphql 這條有缺陷。graphql 的 Query
與 Mutation
都是使用 POST
請求。對不一樣的執行成功的 Mutation
返回不一樣的 200,201,202 仍是比較麻煩。
不過對於錯誤返回不一樣的狀態碼, 打開 devtool 一眼能夠看到紅色的 4XX 信息,也對快速定位錯誤請求有幫助,稍微減小了些煩躁心。
介紹幾種常見的4xx狀態碼
關於400參考 400 BAD request HTTP error code meaning? 這裏有一篇文章,關於4xx狀態碼的選擇,取一張圖出來
因爲 graphql 的強類型 schema,也省了數據輸入輸出的校驗。
對於 Rest API,可使用 JSON Schema 來校驗數據格式。node 也可使用 joi 作數據校驗。
這裏放一份 JSON Schema 的文檔:json-schema.org/
得益於 graphql 的 introspection 與強類型的 schema。graphql 能夠根據源碼以及註釋自動生成文檔,直接使用 graphiql 或者 graphql playground 上查看。
若是你使用 node.js 來寫服務器應用,可使用 apiDoc
另外,注意不要把文檔暴露到生產環境,graphql 須要在生產環境中關掉 introspection。