最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網 會員登陸 & 注冊

應用程序編程接口(API)設計與實踐的借鑒與思考

2021-07-23 19:35 作者:licuihe  | 我要投稿


從md復制過來沒有格式了,可以到鏈接查看


https://gitee.com/cuiheCN/api-design/blob/master/%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%EF%BC%88API%EF%BC%89%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E8%B7%B5%E7%9A%84%E5%80%9F%E9%89%B4%E4%B8%8E%E6%80%9D%E8%80%83.md?


應用程序編程接口(API)設計與實踐的借鑒與思考

前言

眾所周知,當今世界運行在各式各樣的系統(tǒng)上,大多系統(tǒng)由多個模塊或子系統(tǒng)組成。在模塊或子系統(tǒng)交互時一定會涉及到應用程序編程接口(API)。API設計得好可以讓系統(tǒng)后續(xù)發(fā)展順利并且維護方便。本文內容包括API的評價要素與API的設計方法。


誠然想用一套API設計的指導原則套用在五花八門的場景上是不容易的,下面的內容是我結合同事們的意見并參考網上資料總結出來的,希望能在大多數(shù)場景中給API的設計人員一些幫助。鑒于API的設計藝術和技藝總是有新的提升空間并且我們水平有限,所以本文提到的內容也不是固定不變的完美狀態(tài),若您有相關的指導意見或改進建議歡迎告知作者。


成功的系統(tǒng)可能沒有什么閃光點,但是設計師點點滴滴的努力隨處可見。


API的評價要素

清晰易懂的思維模型

API設計最難的部分不是解決系統(tǒng)或模塊之間的交互,而是背后的設計者、開發(fā)者、維護者、使用者之間的溝通與理解。若能在API的設計中體現(xiàn)清晰易懂的思維模型則能讓不同角色快速達成共識,減少出錯提升效率。


簡潔而不簡陋

有時候我們普遍會將API設計得過于復雜,即引入了過多的實現(xiàn)細節(jié)。有時候我們會將問題過度抽象,即不該合并的概念合并了。API涉及的概念應該是即易于理解又簡潔清晰。


完整

API應支持在其基礎上構建完整的應用程序,所有預期的功能都能實現(xiàn)。


容許多個實現(xiàn),也說松耦合或正交性

如果一個API可以有多個完全不同的實現(xiàn),一般來說其已經具備了足夠的抽象也與外部系統(tǒng)或模塊實現(xiàn)了松耦合。


導致可讀性強的代碼

因為代碼被閱讀的時間遠比編寫他們的時間多,所以代碼的可讀性很重要。API設計得好會產生可讀性強的調用代碼。


在不同服務,使用相同的方法,是一種良好的體驗。


API的設計方法

一段佳話 —— POSIX File API

POSIX File API設計于1988年前后,距今30多年。期間計算機硬件和軟件系統(tǒng)發(fā)展了好幾代,F(xiàn)ile API的核心保持了穩(wěn)定。File API提供了清晰的概念模型,幾乎每個用過它的人都能理解其所描述的概念——文件、打開、關閉、讀、寫、路徑。File API支持多種不同實現(xiàn),例如磁盤、管道、內存、網絡、終端等。


更多信息查看IEEE 1003、IEEE 2003、ISO/IEC 9945相關標準。

python中的文件方法


面向“資源”的API設計流程推薦

確定API提供些哪些資源

按照類型分類,確定資源之間的關系(從屬、聚合等)

根據(jù)上述兩個信息,確定資源的命名(car、fuelCar、electricCar)

明確資源要素(ID,屬性)

給資源附加最少的操作方法(增刪改查)

寫文檔

API文檔的重要性不言而喻————當今技術向服務化甚至微服務化發(fā)展,單個應用可能依賴多個服務模塊或子系統(tǒng),每個服務模塊或子系統(tǒng)又在不斷演進。若有準確及時的API文檔則對客戶端開發(fā)調試幫助極大,減少出問題的幾率,提升整體研發(fā)效率。


常見文檔內容:他是什么?成功是什么情況?失敗是什么情況?什么情況下導致失???冪等么?單位是什么?正常值的范圍?副作用?如何使用?常見調用錯誤?什么情況下可以使用(總是存在么)?默認值是多少?默認值是什么含義?


若接口是動名詞描述的,那么文檔也應該是動名詞描述的。

描述資源的文檔應該圍繞資源描述。

描述參數(shù)或字段的可以描述其數(shù)量,值的含義,是否已棄用,描述邊界信息,描述默認值行為,描述其允許的字符,提供可能的示例值,是否必須等。

描述方法或操作的應該說明操作的對象或資源,會產生什么效果。例如:列出用戶的日歷事件。刪除一個位置記錄。


面向“資源”的API設計

資源是API中核心對象的一個抽象。今天“資源”+“操作”這種API設計模式幾乎成為業(yè)界共識。也可以描述成“數(shù)據(jù)模型”+“功能”

例如File API中將文件作為操作的資源。其含義是“可以由一個字符串唯一標識的數(shù)據(jù)記錄”。其中標識方法不甚關鍵,組織結構存儲結構也不在其中。


一般來講,根據(jù)業(yè)務抽象的資源概念應該和日常生活中的概念相似,這樣可以幫助人們更好地建立思維模型。


抽象深度合適

在能滿足需求的情況下,抽象越淺越好。


概念命名

包括接口、資源、集合、方法、消息的命名應該簡單、直觀、一致。

只有在表示一組資源時才使用復數(shù)。

使用美式英語單詞。

使用熟悉的詞,正例delete、remove,反例erase、destory。

對同一概念使用同一單詞,對不同概念使用不同單詞。

使用簡潔的命名但避免籠統(tǒng)的命名。一般使用定語+名詞。反例element、entry、instance、item、object、resource、type、value。正例rowValue。

盡量避免與編程語言中保留字發(fā)生沖突。

資源全名不加版本信息,URL包括版本信息。例


//這是一個日歷事件資源名稱

"//calendar.googleapis.com/users/john smith/events/123"

//這是對應的HTTP URL

"https://calendar.googleapis.com/v3/users/john%20smith/events/123"

用名詞描述資源地址。

產品名,應該由公司市場團隊和產品團隊來命名以保證公司產品名的一致性。 服務名,應符合域名規(guī)范,以確保其可以被解析成網絡地址。 包名,應當盡可能使用產品名+服務名+包名+版本。 集合名,小駝峰復數(shù)形式。 接口名,避免與編程語言的保留字或運行庫沖突,可以使用Api或者Service后綴解決沖突。 方法名,小駝峰,動名詞。動詞時操作,名詞是資源。 消息名,建議附帶Request和Response后綴。 枚舉名,枚舉類型用大駝峰,枚舉值用下劃線分割的全大寫,記得寫默認枚舉值或者未指定枚舉值。 字段名,可以使用全小寫下劃線分割。以符合認知的情況使用復數(shù)形式。表示時間的字段使用time、time_seconds、duration、delay等結尾并且不使用過去式,反例updated_time.日期和時刻使用data結尾。表示數(shù)量的需要包含計量單位以meters、bytes等結尾。表示過濾語義的以filter結尾。 縮寫。只能使用熟知的約定俗成的縮寫,即使這樣在文檔中也應寫明全稱。config,configuration。id,identifier。


資源的標識(ID)設計

資源標識是暴露給用戶的,一般會有三種考慮:字符串作為ID,結構化數(shù)據(jù)作為ID,數(shù)字作為ID。

暫時沒有選擇原則,提供幾個例子供參考:


FIle API中使用了字符串作為文件的標識,這樣容許了Windows系統(tǒng)和Linux系統(tǒng)使用不同的路徑標識其文件。

某銀行系統(tǒng)使用{銀行,存款人標識}這樣的結構化數(shù)據(jù)來表示轉賬賬號

慎用數(shù)字id,除非你考慮過這三個問題:其余兩種方法都不好用?64位整數(shù)夠么?對用戶來講數(shù)字id友好么?

資源的操作在概念上(直覺上)是合理的

前提,資源的定義與抽象是合理的,才能考慮對資源的操作是否是合理的。

標準操作有List、Get、Create、Update和Delete。標準操作都應給予用戶返回,刪除操作返回一個空對象,讓開發(fā)人員確切的掌握接口狀態(tài)。

“操作”+“資源”連起來要符合直覺,聽起來自然。

若是一個耗時操作,應先返回一個統(tǒng)一的耗時對象表示已接收。讓客戶端可以根據(jù)耗時對象獲取進度和結果。


寫入和更新等操作應具備冪等性

冪等性是指多次操作結果和單次操作結果一致。

這種設計的好處顯而易見——客戶端可以簡單地安全的進行重試。

創(chuàng)建類的冪等性實現(xiàn)一般由客戶端創(chuàng)建一個操作id,服務端可以根據(jù)操作id識別重復的操作。當識別到重復的創(chuàng)建操作時應返回第一次成功的信息,因為客戶端可能沒有收到成功的信息。

更新類的操作應該避免使用“Delta”(變化量)語義的接口而應使用“set”(設置成新值)。當然我們也應知道set語義在多客戶端并發(fā)請求時不如delta,應根據(jù)使用情況來定到底是用哪個語義。

刪除類的冪等性一般沒什么問題。也可以使用先獲取再清除這樣的思路。


版本與兼容性

兼容指的是向后兼容,老客戶端訪問同一個主版本的新服務端不會出現(xiàn)錯誤的行為。

這里有一些反面例子:刪除一個方法、字段等。方法、字段等改名。方法名不變但語義或行為變化。

如果一定要發(fā)布不兼容的變更,建議在大版本發(fā)布時發(fā)布不兼容的變更并且保留老接口。老接口標記Deprecation,給客戶端足夠的升級時間。也要記得在過渡期后刪除老接口。

反面例子:通知所有使用服務端API的客戶端同步做一次不兼容更新。難以回退,難以通知所有客戶端,發(fā)布不同步。

一般來講,服務不設版本號,API接口設置版本號。

版本號應該使用語義化 主版本號.小版本號.補丁號。當有不兼容修改時,增加主版本號。當有兼容的功能修改時,增加小版本號。當有兼容的錯誤修復時,增加補丁號。只有主版本號可以編碼在程序包中,小版本號和補丁號寫在配置文件和文檔中。


客戶端批量操作

盡量避免服務端批量操作的API,除非在業(yè)務上服務端做批量非常具有意義,否則應該在客戶端做批量。

服務端批量操作會增加語義和實現(xiàn)的復雜度。例如部分操作成功如何返回,狀態(tài)如何表達。

服務端批量難以容許多種實現(xiàn)。

服務端批量容易被客戶端濫用,給服務器帶來挑戰(zhàn)。

客戶端批量可以做負載均衡。

客戶端批量可以按需做失敗重試策略。


警惕替換式更新

反例看起來是這樣的UpdateFoo(Foo newFoo);

服務端可能已經對此對象做了兼容性更新而客戶端沒有更新,造成錯誤。

多個客戶端更新時互相覆蓋。

推薦操作是在API中引入明確的參數(shù)field指明哪些成員應該被更新。代碼看起來是這樣的:


UpdateFoo {

? Foo newFoo;?

? Object field; // update mask

}

使用已有的錯誤碼

推薦使用已有的標準的錯誤碼,例如HTTP規(guī)范的錯誤碼——200 OK 沒有錯誤,404 NOT_FOUND 找不到指定資源等等。

錯誤處理是客戶端的事情。但是不推薦讓客戶端每API處理超過三種錯誤。

客戶端一般只關心三種錯誤:1 是否需要重試;2 是否需要向上層繼續(xù)拋出;3 做一些其他事。

優(yōu)先考慮使用已有的錯誤碼,將不同的錯誤內容寫到錯誤消息中。

不要假定用戶是API專家,不要假定用戶了解上下文,如果可能應構造錯誤消息以幫助技術用戶相應錯誤,保持錯誤消息簡練要不提供獲取更多信息的鏈接。別忘了錯誤消息本地化。

服務端傳播錯誤時,注意隱藏實現(xiàn)信息和機密信息并且調整錯誤的發(fā)生方為自己。反例"客戶端IP地址不在白名單128.0.0.0/8"。正例"Resource 'xxx' not found." "Resource 'xxx' already exists."


關于http錯誤碼可閱讀:https://httpwg.org/specs/rfc7231.html


其他設計

通過搜索等手段獲取的資源,返回時也應返回資源本身路徑而非搜索路徑。

若允許客戶端提交排序請求,則排序字符串應符合SQL語法。

若允許客戶端請求驗證,則需要返回驗證結果再考慮請求結果。

枚舉值記得定義默認值,一般為0值。

若需要API接收語法內容,則使用ISO 14977的句法來定義語法。(沒有接觸過)

避免使用無符號整型,使用有符號整型但是負數(shù)含義特殊時應記錄在文檔,例如-1表示失敗。

在大多數(shù)返回時都可以進行一個返回前過濾,可選參數(shù)field。

出于對流量的考慮,一些請求資源的接口可以設計其輕量版本。(感覺和上面的field類似)

如果需要可以為資源創(chuàng)建指紋,在請求時附帶資源指紋以利用緩存。(不是很明白,進行弱校驗)

若客戶端的請求的參數(shù)多了,應忽略。若這些多的參數(shù)是服務器返回的參數(shù),應覆蓋。

在創(chuàng)建對象時,其屬性應該是正交的。


其他提醒

不要拼錯單詞。

保持方法的對稱性,有add就有delete或remove,有open就有close。

站在使用者視角,提高用戶體驗。

不要使用過多參數(shù)導致難以理解,反例


?QSlider *slider = new QSlider(12, 18, 3, 13, Qt::Vertical, 0, "volume");

正例


QSlider *slider = new QSlider(Qt::Vertical);

?slider->setRange(12, 18);

?slider->setPageStep(3);

?slider->setValue(13);

?slider->setObjectName("volume");

不推薦使用布爾值作為參數(shù),因為它會混淆否定操作還是否定資源或是否定某個參數(shù),反例


?widget->repaint(false); // 重繪還是不重繪?還是重繪窗口不擦除背景?

正例


?widget->repaint(); // 重繪

?widget->repaintWithoutErasing(); // 重繪不擦除

應用程序編程接口(API)設計與實踐的借鑒與思考的評論 (共 條)

分享到微博請遵守國家法律
万源市| 吴江市| 禹州市| 双辽市| 绥芬河市| 大庆市| 科尔| 丽江市| 内黄县| 温州市| 宽城| 邵东县| 通榆县| 玛沁县| 恩施市| 泰宁县| 鄯善县| 台湾省| 贵港市| 长治县| 丹棱县| 阳高县| 定日县| 依安县| 罗甸县| 陈巴尔虎旗| 柳林县| 惠东县| 米泉市| 望奎县| 上林县| 阜新| 苏州市| 修武县| 岑巩县| 三江| 托克逊县| 蚌埠市| 汶上县| 江油市| 贵州省|