完善的 API 的 4 個基本特徵
如果你正在構建基於 C/S 模型的應用程序,那麼你需要一個應用程序介面(API)。API 就是一種非常清晰而又明確的定義,它是一個 進程 與另一個進程之間明確定義的邊界。Web 應用中我們常見的邊界定義就是 REST/JSON API。
雖然很多開發者可能主要關注在如何讓 API 正常工作(或功能正常),但卻還有一些「非功能性」的要求也是需要他們注意的。所有的 API 必須具備 的 4 個非功能性的要求是:
- 安全
- 文檔
- 驗證
- 測試
安全
在軟體開發中,安全是最基本的要求。對於 API 開發者來說,API 的安全性主要包含以下 4 個方面:
- HTTPS/SSL 證書
- 跨域資源共享
- 身份認證與 JSON Web 令牌
- 授權與作用域
1、HTTPS/SSL 證書
Web 應用的黃金標準是使用 SSL 證書的 HTTPS 協議。Let's Encrypt 可以幫你達到這一目的。Let's Encrypt 來自於非營利性的互聯網安全研究小組(ISRG),它是一個免費的、自動化的、開放的證書頒發機構。
Let's Encrypt 的軟體會為你的域(LCTT 譯註:包含域名、IP 等信息)生成中央授權證書。而正是這些證書確保了從你的 API 到客戶端的數據載荷是點對點加密的。
Let's Encrypt 支持證書管理的多種部署方案。我們可以通過查看 文檔 來找出最適合自己需要的方案。
2、跨域資源共享
跨域資源共享 (CORS)是一個針對瀏覽器的安全策略預檢。如果你的 API 伺服器與發出請求的客戶端不在同一個域中,那麼你就要處理 CORS。例如,如果你的伺服器運行在 api.domain-a.com
並且接到一個來自 domain-b.com
的客戶端的請求,那麼 CORS 就會(讓瀏覽器)發送一個 HTTP 預檢請求,以便查看你的 API 服務是否會接受來自此客戶域的客戶端請求。
「跨域資源共享(CORS)是一種基於 HTTP 頭的機制,這種機制允許伺服器標記除自身源外的其他任何來源(域、方案或埠)。而對於這些被伺服器標識的源,瀏覽器應該允許我們從它們載入資源。」
![CORS 原理](/data/attachment/album/202106/14/155608k4ys6c7llzme4fye.png "CORS principles")
另外,有很多用於 Node.js 的輔助庫來 幫助 API 開發者處理 CORS。
3、身份認證與 JSON Web 令牌
有多種方法可以驗證你的 API 中的認證用戶,但最好的方法之一是使用 JSON Web 令牌(JWT),而這些令牌使用各種知名的加密庫進行簽名。
當客戶端登錄時,身份管理服務會向客戶端提供一個 JWT。然後,客戶端可以使用這個令牌向 API 發出請求,API 收到請求後,從伺服器讀取公鑰或私密信息來驗證這個令牌。
有一些現有的庫,可以幫助我們對令牌進行驗證,包括 jsonwebtoken。關於 JWT 的更多信息,以及各種語言中對其的支持庫,請查看 JWT.io。
import jwt from 'jsonwebtoken'
export default function (req, res, next) {
// req.headers.authorization Bearer token
const token = extractToken(req)
jwt.verify(token, SECRET, { algorithms: ['HS256'] }, (err, decoded) => {
if (err) { next(err) }
req.session = decoded
next()
})
}
4、授權與作用域
認證(或身份驗證)很重要,但授權同樣很重要。也就是說,經過驗證的客戶端是否有許可權讓伺服器執行某個請求呢?這就是作用域的價值所在。當身份管理伺服器對客戶端進行身份認證,且創建 JWT 令牌時,身份管理服務會給當前客戶提供一個作用域,這個作用域將會決定當前經過驗證的客戶的 API 請求能否被伺服器執行。這樣也就免去了伺服器對訪問控制列表的一些不必要的查詢。
作用域是一個文本塊(通常以空格分隔),用於描述一個 API 端點的訪問能力。一般來說,作用域被分為資源與動作。這種模式對 REST/JSON API 很有效,因為它們有相似的 RESOURCE:ACTION
結構。(例如,ARTICLE:WRITE
或 ARTICLE:READ
,其中 ARTICLE
是資源,READ
和 WRITE
是動作)。
作用域的劃分讓我們的 API 能夠專註於功能的實現,而不是去考慮各種角色和用戶。身份訪問管理服務可以將不同的角色和用戶分配不同的許可權範圍,然後再將這些不同的作用域提供給不同的 JWT 驗證中的客戶。
總結
當我們開發和部署 API 時,安全應該一直是最重要的要求之一。雖然安全性是一個比較寬泛的話題,但如果能解決上面四個方面的問題,這對於你的 API 來說,在生產環境中將會表現得更好。
文檔
有什麼能比沒有文檔更糟糕?過期的文檔。
開發者對文檔真的是又愛又恨。儘管如此,文檔仍然是 API 定義是否完善的一個關鍵部分。開發者需要從文檔中知道如何使用這些 API,且你創建的文檔對於開發者如何更好地使用 API 也有著非常巨大的作用。
創建 API 文檔,我們需要關注下面三個方面:
- 開發者入門文檔(自述文件/基本介紹)
- 技術參考(規範/說明書)
- 使用方法(入門和其他指南)
1、入門文檔
在構建 API 服務的時候,你需要明確一些事情,比如:這個 API 是做什麼的?如何建立開發者環境?如何測試該服務?如何提交問題?如何部署它?
通常我們可以通過自述(README
)文件來回答上面的這些問題,自述文件一般放在你的代碼庫中,用於為開發者提供使用你項目的最基本的起點和說明。
自述文件應該包含:
- API 的描述
- 技術參考與指南的鏈接
- 如何以開發者的身份設置你的項目
- 如何測試這個項目
- 如何部署這個項目
- 依賴管理
- 代碼貢獻指南
- 行為準則
- 許可證
- 致謝
你的自述文件應該簡明扼要;你不必解釋每一個方面,但要提供足夠的信息,以便開發者在熟悉你的項目後可以進一步深入研究。
2、技術參考
在 REST/JSON API 中, 每一個具體的 端點 都對應一個特定的功能,都需要一個具體的說明文檔,這非常重要。文檔中會定義 API 的描述,輸入和可能的輸出,並為各種客戶端提供使用示例。
OpenAPI 是一個創建 REST/JSON 文檔的標準, 它可以指導你完成編寫 API 文檔所需的各種細節。OpenAPI 還可以為你的 API 生成演示文檔。
3、使用方法
對於 API 的用戶來說,僅僅只有技術說明是不夠的。他們還需要知道如何在一些特定的情況和場景下來使用這些 API,而大多數的潛在用戶可能希望通過你的 API 來解決他們所遇到的問題。
向用戶介紹 API 的一個好的方法是利用一個「開始」頁面。「開始」頁面可以通過一個簡單的用例引導用戶,讓他們迅速了解你的 API 能給他們能帶來的益處。
總結
對於任何完善的 API,文檔都是一個很關鍵的組成部分。當你在創建文檔時,你需要關注 API 文檔中的如何入門、技術參考以及如何快速開始等三個方面,這樣你的 API 才算是一個完善的 API。
驗證
API 開發過程中經常被忽視的一個點就是驗證。它是一個驗證來自外部來源的輸入的過程。這些來源可以是客戶端發送過來的 JSON 數據,或者是你請求別人的服務收到的響應數據。我們不僅僅要檢查這些數據的類型,還要確保這些數據確實是我們要的數據,這樣可以消除很多潛在的問題。了解你的邊界以及你能控制的和不能控制的東西,對於 API 的數據驗證來說是一個很重要的方面。
最好的策略是在進入數據邏輯處理之前,在你能控制的邊界的邊緣處進行數據的驗證。當客戶端向你的 API 發送數據時,你需要對該數據做出任何處理之前應用你的驗證,比如:確保 Email 是真實的郵件地址、日期數據有正確的格式、字元串符合長度要求。
這種簡單的檢查可以為你的應用增加安全性和一致性。還有,當你從某個服務接收數據時,比如資料庫或緩存,你需要重新驗證這些數據,以確保返回的結果符合你的數據檢查。
你可以自己手寫這些校驗邏輯,當然也可以用像 Lodash 或 Ramda 這樣的函數庫,它們對於一些小的數據對象非常有用。像 Joi、Yup 或 Zod 這樣的驗證庫效果會更好,因為它們包含了一些常見的驗證方法,可以節省你的時間和精力。除此,它們還能創建一個可讀性強的模式。如果你需要看看與語言無關的東西,請看 JSON Schema。
總結
數據驗證雖然並不顯眼和突出(LCTT 譯註:跟 API 的功能實現以及其他幾個方面比),但它可以幫你節省大量的時間。如果不做驗證,這些時間將可能被用於故障排除和編寫數據遷移腳本。真的不要相信你的客戶端會發送乾淨的數據給你,也不要讓驗證不通過的數據滲入到你的業務邏輯或持久數據存儲中去。花點時間驗證你的 API 收到的數據和請求到的響應數據,雖然在前期你可能會感到一些挫折和不適,但這總比你在後期花大量時間去做各種數據收緊管制、故障排除等要容易得多。
測試
測試是軟體開發中的最佳實踐,它應該是最主要的非功能性的要求。對於包括 API 在內的任何項目,確定測試策略都是一個挑戰,因為你自始至終都要掌握各種約束,以便相應的來制定你的測試策略。
集成測試 是測試 API 的最有效的方法之一。在集成測試模式中,開發團隊會創建一個測試集用來覆蓋應用流程中的某些部分,從一個點到另一個點。一個好的集成測試流程包括測試 API 的入口點以及模擬請求到服務端的響應。搞定這兩點,你就覆蓋了整個邏輯,包括從 API 請求的開始到模擬伺服器的響應,並返回數據給 API。
雖然使用的是模擬,但這種方法讓能我們專註於代碼邏輯層,而不需要去依賴後端服務和展示邏輯來進行測試。沒有依賴的測試會更加可靠、更容易實現自動化,且更容易被接入持續集成管道流。
集成測試的實施中,我會用 Tape、Test-server 和 Fetch-mock。這些庫讓我們能夠從 API 的請求到數據的響應進行隔離測試,使用 Fetch-mock 還可以將出站請求捕獲到持久層。
總結
雖然其他的各種測試和類型檢查對 API 也都有很好的益處,但集成測試在流程效率、構建和管理時間方面卻有著更大的優勢。使用 Fetch-mock 這樣的工具,可以在服務邊界提供一個乾淨的模擬場景。
專註於基礎
不管是設計和構建應用程序還是 API,都要確保包含上面的四個基本要素。它們並不是我們唯一需要考慮的非功能性需求,其他的還包括應用監控、日誌和 API 管理等。即便如此,安全、文檔、驗證和測試這四個基本點,對於構建任何使用場景下的完善 API 都是至關重要的關注點。
via: https://opensource.com/article/21/5/successful-apis
作者:Tom Wilson 選題:lujun9972 譯者:ywxgod 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive