1. <em id="2qvri"><tr id="2qvri"></tr></em>
      1. 首頁»NodeJS»編寫 Node.js Rest API 的 10 個最佳實踐

        編寫 Node.js Rest API 的 10 個最佳實踐

        來源:王仕軍 發布時間:2017-03-03 閱讀次數:

          Node.js 除了用來編寫 WEB 應用之外,還可以用來編寫 API 服務,我們在本文中會介紹編寫 Node.js Rest API 的最佳實踐,包括如何命名路由、進行認證和測試等話題,內容摘要如下:

        1. 正確使用 HTTP Method 和路由
        2. 正確的使用 HTTP 狀態碼
        3. 使用 HTTP Header 來發送元數據
        4. 為 REST API 挑選合適的框架
        5. 要對 API 進行黑盒測試
        6. 使用基于 JWT 的無狀態的認證機制
        7. 學會使用條件請求機制
        8. 擁抱接口調用頻率限制(Rate-Limiting)
        9. 編寫良好的 API 文檔
        10. 對 API 技術演化保持關注

         1. 正確使用 HTTP Method 和路由

          試想你正要構建一個 API 用來創建、更新、獲取、刪除用戶,對于這些操作,HTTP 規范里面已經有了現成的操作:POST、PUT、GET、DELETE,建議直接使用他們來描述接口的行為。

          至于路由的命名,應該使用名詞或名詞性短語來作為資源標識符,比如上文提到的用戶管理的例子,路由就應該長這樣:

        • POST /users 或者 PUT /users/:id 用來創建新用戶;
        • GET /users 用來獲取用戶列表;
        • GET /users/:id 用來獲取單個用戶;
        • PATCH /users/:id 用來更新用戶信息;
        • DELETE /users/:id 用來刪除用戶;

         2. 正確的使用 HTTP 狀態碼

          如果服務器端在請求處理的過程中出錯了,你必須設置正確的響應狀態碼,具體如下:

        • 2xx,表示一切正常;
        • 3xx,表示資源位置已經更改;
        • 4xx,表示因為客戶端錯誤而導致請求無法被處理,比如參數校驗沒通過;
        • 5xx,表示因為服務器錯誤導致請求無法被處理,比如服務端拋了異常;

          如果你使用 express,設置狀態碼非常簡單:res.status(500).send({ error: 'Internal server error happend' }),如果使用了 restify,也是類似的:res.status(201)。

          如果想看完整的 HTTP 狀態碼,點擊這里

         3. 使用 HTTP Header 來發送元數據

          如果想要發送關于響應體數據的元數據,可以使用 Header ,Header 可以包含的常見元數據包括如下幾類:

        • 分頁信息;
        • 頻率限制信息;
        • 認證信息;

          如果你需要在 Header 中發送自定義的元數據,最好的做法是在 Header 名稱前面加 X,例如,需要發送 CSRF Token 的時候,實際的 Header 應該命名為:X-CSRF-Token,然而,這種 Header 在 RFC 6648 中已經被廢棄了。API 在設置自定義 Header 的時候還要盡可能避免命名沖突,比如為了達到這個目的OpenStack 為所有 API 的自定義 Header 都加上了 OpenStack 的前綴:

        OpenStack-Identity-Account-ID  
        OpenStack-Networking-Host-Name  
        OpenStack-Object-Storage-Policy
        

          需要注意的是,雖然 HTTP 規范中沒有規定 Header 的大小,但是 Node.js 中 Header 的大小被限制在了 80KB。官方原文如下:

        不要讓 HTTP Header ,包括其中狀態碼那行的整體大小超過 HTTP_MAX_Header_SIZE,這樣做的目的是為了防御基于 Header 的 DDOS 攻擊。點擊這里

         4. 為 REST API 挑選合適的框架

          根據你的實際場景挑選合適的框架是非常重要的,Node.js 中的框架大致介紹如下:

          Express、Koa、HAPI

          ExpressKoaHAPI 主要是用來構建瀏覽器 WEB 應用,因為他們都支持服務端模板渲染,雖然這只是他們眾多功能中的一個。如果你的應用需要提供用戶界面,那么這三個就是不錯的選擇。

          Restify

          而 Restify 是專門用來創建符合 REST 規范的服務的,他誕生的目的就是幫你構建嚴格意義上的、可維護的 API 服務。Restify 內置了所有請求處理函數的 DTrace 支持。并且已經被 npmnetflix 用來在生產環境提供重要的服務。

         5. 要對 API 進行黑盒測試

          測試 API 的最好辦法是對他們進行黑盒測試,黑盒測試是一種不關心應用內部結構和工作原理的測試方法,測試時系統任何部分都不應該被 mock。

          supertest 是可以用來對接口進行黑盒測試的模塊之一,下面是基于測試框架 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);
          });
        });
        

          可能有人會問:API 服務所連接的數據庫里面的數據是如何寫進去的呢?

          通常來說,你寫測試的時候,要盡可能不對系統狀態做假設,然而在某些場景下,你需要準確的知道系統當前所處的狀態以增加更多的斷言來提高測試覆蓋率。如果你有這種需求,你可以試用如下的方法對數據庫進行預填充:

        • 選擇生產環境數據的子集來運行黑盒測試;
        • 運行黑盒測試之前把手工構造的數據填充到數據庫中。

          此外,有了黑盒測試并不意味著不需要單元測試,針對 API 的單元測試還是需要編寫的。

         6. 使用基于 JWT 的無狀態的認證機制

          因為 Rest API 必須是無狀態的,因此認證機制也需要是無狀態的,而基于 JWT(JSON Web Token) 的認證機制是無狀態認證機制中的最佳解決方案。

          JWT 的認證機制包含三部分:

        1. Header:包含 token 的類型和哈希算法;
        2. payload:包含聲明信息;
        3. signature:JWT 實際上并不是對 payload 進行加密,只是對其做了簽名;

          為 API 添加基于 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' }
        });
        

          有了如上的代碼,你的 API 就有了 JWT 的保護。如果要訪問這種被保護的接口,需要使用 Authorization Header 來提供 token,比如:

        curl --Header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" my-website.com
        

          你可能注意到了,JWT 模塊并不依賴任何數據存儲層,這是因為 token 本身是可以單獨被校驗的,token 里面的 payload 甚至可以包含 token 的簽名時間、有效期限。

          此外,你還需要確保,所有的 API 接口只能通過更安全的 HTTPS 鏈接來訪問。

         7. 學會使用條件請求機制

          條件請求機制是基于不同的 Header 表現出不同的行為的機制,可以認為這些 Header 就是請求處理方式的先決條件,如果條件滿足,請求處理方式就會有所不同。

          可以利用這些 Header 檢測服務器上的資源版本是否匹配特定的資源版本,這些 Header 的取值可以是如下的內容:

        • 資源的最后修改時間;
        • 資源的標簽(隨資源變化而變化);

          具體來說:

        • Last-Modified:標識資源的最新修改時間;
        • Etag:標識資源的標簽;
        • If-Modified-Since:結合 Last-Modified Header 使用;
        • If-Non-Match:結合 Etag 使用;

          下面來看一個實際的例子:

          客戶端不知道 doc 資源的任何版本,所以請求時即不能提供 If-Modified-Since,也不能提供 If-Non-Match 兩個 Header,然后服務端在響應中會增加 Etag 和 Last-Modified 兩個 Header。

          nodejs-resftul-api-with-conditional-request-without-previous-versions.png

          接下來,客戶端再次請求相同的資源的時候,就可以帶上 If-Modified-Since 和 If-Non-Match 這兩個 Header 了,然后如果服務器端會檢查資源是否修改,如果沒有修改,直接返回 304 - Not Modified 狀態碼,而不重復發送資源的內容。

          nodejs-resftul-api-with-conditional-request-with-previous-versions.png

         8. 擁抱接口調用頻率限制(Rate-Limiting)

          頻率限制是用來控制調用方有對接口發起請求的次數,為了讓你的 API 用戶知道他們還剩下多少余額,可以設置下面的 Header:

        • X-Rate-Limit-Limit:特定時間段內允許的最多請求次數;
        • X-Rate-Limit-Remaining:特定時間段內剩余的請求次數;
        • X-Rate-Limit-Reset:什么時候請求頻率限制次數會重置;

          大多數的 WEB 框架都支持上面這些 Header,如果內置不支持,也可以找到插件來支持,比如,如果你使用了 koa,可以使用 koa-rate-limit

          需要注意的是,不同的 API 服務提供商頻率限制的時間窗差異會很大,比如 GitHub 是 60 分鐘,而 Twitter 是 15 分鐘。

         9. 編寫良好的 API 文檔

          編寫 API 的目的當然是讓別人使用并受益,提供良好的接口文檔至關重要。下面這兩個開源項目可以幫你創建 API 文檔:

          如果你愿意使用第三方文檔服務商,可以考慮 Apiary

         10. 對 API 技術演化保持關注

          過去幾年中,API 技術方案領域出現了兩種新的查詢語言,分別是 Facebook 的 GraphQL 和 Netflix 的 Falcor,為什么需要他們呢?

          試想這種 API 接口請求:/org/1/space/2/docs/1/collaborators?include=email&page=1&limit=10,類似的情況會讓 API 很快失控,如果你希望所有接口能返回類似的響應格式,那么 GraphQL 和 Falcor 就能幫你解決這個問題。

          關于 GraphQL

        GraphQL 是一種用于 API 的查詢語言,也是一種基于現有數據處理數據查詢的運行時。GraphQL 為您的 API 中的數據提供了一個完整和可理解的描述,使用戶能夠準確地詢問他們需要什么,使得隨著時間推移的 API 演化更容易,GraphQL 還有強大的開發工具支持。 到這里閱讀更多。

          關于 Falcor

        Falcor 是支撐著 Netflix UI 的創新數據平臺。Falcor 允許你將所有后端數據建模為 Node.js 服務商的單個虛擬 JSON 對象。在客戶端可以使用熟悉的 JavaScript 操作、處理遠程JSON對象。如果你知道你的數據,你就知道你的 API 長啥樣。 到這里閱讀更多。

         能帶來靈感的優秀 API 設計

          如果你正在開發 Rest API 或者準備改進老版本的 API,這里收集了幾個在線上提供服務、設計優秀并且非常直接借鑒的 API:

          希望讀到這里的同學對如何用 Node.js 編寫良好的 API 有更好的理解,如果有建議,歡迎評論中提出。

          英文原文:https://blog.risingstack.com/10-best-practices-for-writing-node-js-rest-apis/

        QQ群:WEB開發者官方群(515171538),驗證消息:10000
        微信群:加小編微信 849023636 邀請您加入,驗證消息:10000
        提示:更多精彩內容關注微信公眾號:全棧開發者中心(fsder-com)
        網友評論(共2條評論) 正在載入評論......
        理智評論文明上網,拒絕惡意謾罵 發表評論 / 共2條評論
        登錄會員中心
        江苏快3投注技巧