Node.js REST API的10個最佳實踐
在本文中,我們將介紹編寫Node.js REST API的最佳實踐,包括命名路由,身份驗證,黑盒測試以及為這些資源使用適當的快取頭等主題。
#1 - 使用HTTP方法和API路由
想象一下,您正在構建一個Node.js RESTful API,用於建立,更新,檢索或刪除使用者。對於這些操作HTTP已經有足夠的工具集:POST,PUT,GET,PATCH或DELETE。
作為最佳實踐,API路由應始終使用名詞作為資源識別符號。比如使用者的資源,路由可能如下所示:
POST /user或者PUT /user:/id建立一個新使用者,
GET /user 檢索使用者列表,
GET /user/:id 檢索使用者,
PATCH /user/:id 修改現有使用者記錄,
DELETE /user/:id 刪除使用者
“API路由應始終使用名詞作為資源識別符號!”
#2 - 正確使用HTTP狀態程式碼
如果在提供請求時出現問題,必須在響應中為其設定正確的狀態程式碼:
2xx一切都好,
3xx,資源被移動,
4xx,由於客戶端錯誤(如請求不存在的資源)而無法滿足請求,
5xx,API方面出現問題(就像發生異常一樣)。
如果使用Express,設定狀態程式碼就像res.status(500).send({error: 'Internal server error happened'})。
Restify相似:res.status(201)。
#3 - 使用HTTP標頭髮送元資料
要附加有關要傳送的有效負荷內容的元資料,請使用HTTP標頭。像這樣的標題可以是以下資訊:
分頁,
限速,
或認證。
可以在ofollow,noindex" target="_blank">此處 找到標準化HTTP標頭的列表
如果需要在標題中設定任何自定義元資料,最佳做法是為它們新增字首X。例如,如果使用的是CSRF令牌,那麼將它們命名為常用(但非標準)方式X-Csrf-Token。然而,對於RFC 6648,他們已被棄用。新API應盡最大努力不使用可能與其他應用程式衝突的標頭名稱。例如,OpenStack為其標頭新增字首OpenStack:
OpenStack-Identity-Account-ID
OpenStack-Networking-Host-Name
OpenStack-Object-Storage-Policy
請注意,HTTP標準沒有定義標頭的任何大小限制; 但是,出於實際原因,Node.js(撰寫本文時)對頭物件施加了80KB的大小限制。
“不要允許HTTP標頭(包括狀態行)的總大小超過HTTP_MAX_HEADER_SIZE。此檢查用於保護嵌入器免受拒絕服務攻擊“。
來自Node.js HTTP解析器
#4 - 為Node.js REST API選擇正確的框架
選擇最適合用例的框架非常重要。
Express,Koa或Hapi
Express,Koa和Hapi可用於建立瀏覽器應用程式,它們還支援模板和渲染 。
RESTify
另一方面,Restify專注於幫助您構建REST服務。它的存在是為了讓您構建可維護和可觀察的“嚴格”API服務。Restify還為所有處理程式提供自動DTrace支援。
Restify用於主要應用程式(如npm或Netflix)的生產中。
“Restify的存在是為了讓你構建可維護和可觀察的”嚴格“API服務。”
#5 - 黑盒測試你的Node.js REST API
測試REST API的最佳方法之一是將它們視為黑盒子。
黑盒測試是一種測試應用程式功能的方法,不需要了解其內部結構或工作原理。因此,沒有任何依賴項被模擬或存根,但系統作為一個整體進行測試。
其中一個可以幫助您進行黑盒測試Node.js REST API的模組是最優秀的。
檢查使用者是否使用測試執行器mocha返回的簡單測試用例可以這樣實現:
const request = require('supertest')
describe('GET /user/:id', function() {
it('returns a user', function() {
// newer mocha versions accepts promises as well
return request(app)
.get('/user')
.set('Accept', 'application/json')
.expect(200, {
id: '1',
name: 'John Math'
}, done)
})
})
您可能會問:資料如何填充到為REST API提供服務的資料庫中?
一般來說,以一種儘可能少的關於系統狀態的假設的方式編寫測試是一種很好的方法。可以使用以下方法之一使用測試資料填充資料庫:
在已知的生產資料子集上執行黑盒測試場景,
在執行測試用例之前,使用精心設計的資料填充資料庫。
當然,黑盒測試並不意味著你不必進行單元測試,你仍然需要為你的API 編寫單元測試。
#6 - 基於JWT的無狀態認證
由於REST API必須是無狀態的,因此身份驗證層也是如此。為此,JWT (JSON Web Token)是理想的選擇。
JWT由三部分組成:
標頭,包含令牌型別和雜湊演算法
有效負載payload,包含宣告定義
簽名 ,(JWT不加密有效載荷,只需簽名!)
將基於JWT的身份驗證新增到您的應用程式非常簡單:
const koa = require('koa')
const jwt = require('koa-jwt')
const app = koa()
app.use(jwt({
secret: 'very-secret'
}))
// Protected middleware
app.use(function *(){
// content of the token will be available on this.state.user
this.body = {
secret: '42'
}
})
要訪問上面這個受保護的端點,必須在Authorization標頭欄位中提供令牌。
curl --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" my-website.com
注意JWT模組不依賴於任何資料庫層。因為所有JWT令牌都可以自己驗證,並且它們也可以包含生存時間值。
此外,始終必須確保只能通過使用HTTPS的安全連線訪問所有API端點。
#7 - 使用條件請求
條件請求是HTTP請求根據特定的HTTP標頭執行不同的HTTP請求。可以將這些標頭視為先決條件:如果滿足這些標頭,請求將以不同的方式執行。
根據特定的HTTP標頭執行不同的條件請求
<p class="click-to-tweet-button">
<ahref="https://twitter.com/share?text=%22Conditional%20requests%20are%20executed%20differently%20depending%20on%20specific%20HTTP%20headers%22%20via%20%40RisingStack;url=https://blog.risingstack.com/10-best-practices-for-writing-node-js-rest-apis" target="_blank" c>Click To Tweet</a>
</p>
這些標頭嘗試檢查儲存在伺服器上的資源版本是否與同一資源的指定版本匹配。由於這個原因,這些標題可以是:
上次修改的時間戳,
或實體標籤,每個版本都有所不同。
這些標題可以是:
Last-Modified (表示上次修改資源的時間),
Etag (表示實體標籤),
If-Modified-Since (與Last-Modified標題一起使用),
If-None-Match (與Etag標題一起使用),
#8 - 擁抱速率限制
速率限制用於控制指定消費者可以向API傳送的請求數量。
要告訴你的API使用者他們剩下多少請求,請設定以下標頭:
X-Rate-Limit-Limit,給定時間間隔內允許的請求數
X-Rate-Limit-Remaining,在同一間隔內剩餘的請求數,
X-Rate-Limit-Reset,速率限制將被重置的時間。
大多數HTTP框架都支援開箱即用(或使用外掛)。例如,如果您使用Koa,則有koa-ratelimit包。
請注意,時間視窗可能因不同的API提供程式而異 - 例如,GitHub使用一小時,而Twitter則為15分鐘。
#9 - 建立適當的API文件
編寫API文件以便其他人可以使用它們,從中受益。為Node.js REST API提供API文件至關重要。
以下兩個開源專案是可以幫助您為API建立文件:
API藍圖
swagger
#10 - 不要錯過API的未來
在過去幾年中,出現了兩種主要的API查詢語言 - 即來自Facebook的GraphQL和來自Netflix的Falcor。為什麼我們需要它們呢?
想象一下一下RESTful資源請求:
/org/1/space/2/docs/1/collaborators?include=email&page=1&limit=10
這很容易失控 - 因為你希望始終為所有模型獲得相同的響應格式。這就是GraphQL和Falcor可以提供幫助的地方。
GraphQL是API的查詢語言,使用現有資料完成這些查詢。GraphQL提供了API中資料的完整且易於理解的描述,使客戶能夠準確地詢問他們需要什麼,僅此而已,使API隨著時間的推移更容易發展,並支援強大的開發人員工具。
關於Falcor
Falcor是為Netflix使用者介面提供支援的創新資料平臺。Falcor允許您將所有後端資料建模為節點伺服器上的單個Virtual JSON物件。在客戶端上,您可以使用熟悉的JavaScript操作(如get,set和call)來處理遠端JSON物件。如果您瞭解自己的資料,就會知道自己的API。