Google Cloud的API設(shè)計,google cloud platformGoogle Cloud的API設(shè)計最近(很久前)在設(shè)計API接口的時候發(fā)現(xiàn)了一些很難取舍的地方,就看了下業(yè)界領(lǐng)先的企業(yè)都是怎么設(shè)計類似API的,發(fā)現(xiàn)了很多之前設(shè)計的缺陷和一些新的思路。主要參考了AWS和Google Cloud的API設(shè)計......
最近(很久前)在設(shè)計API接口的時候發(fā)現(xiàn)了一些很難取舍的地方,就看了下業(yè)界領(lǐng)先的企業(yè)都是怎么設(shè)計類似API的,發(fā)現(xiàn)了很多之前設(shè)計的缺陷和一些新的思路。主要參考了AWS和Google Cloud的API設(shè)計,兩家的設(shè)計可以說是把兩個不同的風(fēng)格發(fā)揮到了極致,做同樣的事情API的各個方面都可以設(shè)計的完全不一樣。Google有一個自己的API Design規(guī)范可以在網(wǎng)上找到,不過真實的GCE API規(guī)范略有一些出入。而AWS的API設(shè)計是沒有什么文檔的,只能通過現(xiàn)有的API進(jìn)行逆向工程來反推設(shè)計理念。這篇文章會比較瑣碎,更像是一個讀書筆記,細(xì)節(jié)的東西會比較多。
Google Cloud API
由于Google的文檔比較詳細(xì)了,就先照著Google的文檔來講,而Google的API是按照REST風(fēng)格來的,而REST只是一種紙面的模式,每家的實現(xiàn)可能都不一樣,我們就來看下Google眼里的REST是什么樣的。然后介紹一下REST API的一些局限和缺點以及Google的解決方式。
最權(quán)威的REST當(dāng)然還是得去看論文了,不過對于普通開發(fā)者來講HTTP的REST就是一個URL指向一個資源,然后這個URL上通過不同的HTTP方法來實現(xiàn)對這個資源的不同操作。簡單來說就是指向資源的URL+HTTP方法就構(gòu)成了常見的REST API。這里面每一個部分都有很多門道。
URL
URL可以分成好幾個組成部分
1.域名,不同的域名可以區(qū)分這個網(wǎng)站提供的不同API服務(wù)。比如一個圖書,一個電影,域名就應(yīng)該是http://library.oilbeater.cn和http://moive.oilbeater.cn
2.版本號,對應(yīng)不同的歷史版本,可以是v1,v2,也可以是alpha,beta這樣
3.資源集合,書店里可能會有多種資源的集合,比如圖書,報紙,影碟,這就需要用資源集合來區(qū)分/books,/newspapers,/cds等等
4.資源名稱,這時候才真正到具體的資源,一個圖書可能就是http://library.oilbeater.com/v1/books/book1
5.子資源,有時候一層的資源模型不能滿足現(xiàn)實的需求,比如圖書館的檢索是按照書架來的,需要先知道在哪個書架才能找到書,就需要在中間插一層資源。最后的url可能就變成了http://library.oilbeater.com/v1/shelves/shelf1/books/book1
6.重復(fù)34
資源命名
1.資源名必須是合法的C語言變量名,這個規(guī)范主要是為了代碼和SDK的一致性,不然有個減號這樣的字符很多語言的SDK里這個資源對象你就不得不換個名字或者寫法了,很容易造成不一致,一些自動生成SDK的工具也會失敗
2.資源集合必須是復(fù)數(shù)
3.不要用縮寫避免不必要的歧義
4.不要用過于泛化的資源類型,像type,object,element,resource這樣的命名一來不是很清楚,二來很容易和編程語言的關(guān)鍵字撞名字,人為增加編程難度。方法
常用的HTTP方法有GET,POST,PUT,DELETE稍微常見的還有HEAD,PATCH,不太常見的還有COPY,LINK,LOCK,VIEW等等。由于HTTP是純文本的協(xié)議,并沒有規(guī)定只能用哪幾個方法,只要服務(wù)端做處理就可以自己再自定義其他方法的,比如Google自己就實現(xiàn)了一個BATCH來做批量處理。
每個HTTP方法和以對應(yīng)不同的語義,而且這些語義像GET是獲取,POST創(chuàng)建PUT更新DELETE刪除基本上大家都是形成共識的,API最后的統(tǒng)一性會很好。REST的初衷也是讓資源盡可能的多,每個資源的方法盡可能的只有標(biāo)準(zhǔn)的幾個方法,這樣所有的API看起來長得都很像,學(xué)習(xí)和實現(xiàn)的成本都會很低。下面說一下具體的每個方法需要注意的一些事情
List
1.需要用GET方法url指向資源集合,并返回資源的列表
2.List返回的內(nèi)容最好有分頁信息,而不是簡單的一個資源列表,便于前端的展示并減少每次拿所有數(shù)據(jù)的性能消耗
3.資源列表需要是有序的,如果兩次請求同樣資源順序完全不一樣前端再不處理就會有奇奇怪怪的現(xiàn)象
4.List需要提供簡單的按照某個字段排序,filter方法,更復(fù)雜的過濾查詢需要單獨的方法
5.可以返回一些metadata,比如資源數(shù)量,資源集合的信息等
Create
1.POST方法URL指向資源集合,創(chuàng)建成功需要返回這個資源,而不是只有一個201的狀態(tài)碼
2.需要允許client自己指定resourceid,而不是全部由系統(tǒng)自動生成。這樣第三方系統(tǒng)可以根據(jù)情況進(jìn)行重試和重復(fù)檢查。不然一個create請求中間路徑上有重試就會生成多個id不同的資源,后續(xù)處理會很麻煩。
Update
1.PUT或者PATCH方法URL指向具體資源,更新成功需要返回資源實體
2.PUT一般用于整個資源實體的更新,而PATCH只更新某個字段。對于一個復(fù)雜的有大量字段的資源,最好兩種API都提供,而不是只提供一個PUT。只提供一個PUT即使只更新一個字段也需要傳遞完整的資源實體,很多情況下是沒必要的
用戶自定義方法
由于HTTP的標(biāo)準(zhǔn)方法是有限的,而很多語義是標(biāo)準(zhǔn)方法不能表示的,比如需要把書從一個書架移動到另一個書架就很難用標(biāo)準(zhǔn)方法表示,這就需要用戶自定義方法。定義HTTP方法理論上沒問題,但很多第三方庫并不支持這種方法,這種API給別人看也會比較奇怪,所以通常會把方法加在url里,通常是加在資源名稱后面。比如移動一本書就可以是/books/book1:move
1.通常的做法是用『/』來做URL的分隔,但是在Google的規(guī)范里用的是用『:』因為/分隔會有歧義,不知道后面的到底是一個子資源還是一個用戶自定義方法。聽起來很有道理的樣子,但是在GCE的API里并沒這么做也是用的『/』
2.盡管URL里有了自定義方法,HTTP方法還是盡量用符合語義的,比如更新類的操作都用PUT
3.現(xiàn)實中很多操作都是標(biāo)準(zhǔn)HTTP方法表示起來很苦難的,比如重啟機器,發(fā)快遞郵件,賬號登錄這些,可以想一下這些操作如何用HTTP標(biāo)準(zhǔn)方法來設(shè)計API
標(biāo)準(zhǔn)字段
不同的資源有許多共同的屬性字段,由于每個資源對應(yīng)的API可能是由不同人在不同時間完成的,所以需要有個約定好的公共字段的命名,不然到最后會出現(xiàn)混亂的情況。比如資源需要有個id表示,就會出現(xiàn)不同資源有的叫uuid,有的叫id,有的叫resourceid;創(chuàng)建時間又有createdat,createddatetime,createdtime,分頁又有pagetoken,nextpage,pagenum諸如此類不一致的情況。同樣一些字段的類型也需要統(tǒng)一,比如時間使用時間戳還是標(biāo)準(zhǔn)時間,帶不帶時區(qū)。
除了正常的返回就是錯誤返回也要有統(tǒng)一的格式。錯誤信息需要包含errorcode,errormessage和errordetail。其中errormessage是用來返回給最終用戶的,而errordetail則用于內(nèi)部人源進(jìn)行錯誤排查。
REST的缺陷
盡管REST API的設(shè)計原則在現(xiàn)實中使用的很廣,但是這種設(shè)計也是有很多局限性的。
1.層級設(shè)計很容易過多,比如在公有IAAS中需要獲得一privateip的信息,這個ip可能是屬于某塊網(wǎng)卡的,網(wǎng)卡屬于某個機器,機器屬于某個subnet,subnet屬于某個vpc,vpc屬于某個region。設(shè)計出來的api就變成了/regions/regionid/vpcs/vpcid/subnets/subnetid/instances/instanceid/nics/nicsid/privateips/privateipid這種API直接上就會覺得不合理。而且仔細(xì)考慮機器是不是應(yīng)該屬于subnet,privateip是不是應(yīng)該直接是subnet的子資源,會有很多需要考慮的地方。
2.標(biāo)準(zhǔn)HTTP方法大多是操縱整個資源,而這個粒度在一些情況下太粗了。比如同樣是更新一個主機的操作,更新主機的一個tag和更新主機的name都是PUT一個資源實例url,而更改安全組將主機狀態(tài)設(shè)置成停止也是同樣的PUT方法和url就會有些不合理。盡管都是更新操作,但是更新的字段不同,功能不同,重要性也不同,用同樣的大PUT就會不合適。而且這些字段可能會對應(yīng)著不同的權(quán)限操作,如果任何更新都是同樣的方法,之后細(xì)粒度的權(quán)限控制也會變得十分痛苦。
3.涉及多資源的操作會很難設(shè)計。REST的思想是對資源進(jìn)行操作,但現(xiàn)實中一個操作可能會對應(yīng)多個資源,這時候?qū)τ诙鄠€不同資源關(guān)系的操作REST設(shè)計起來就比較頭疼了。比如給一個主機加一個eip,那么這個操作肯定要用到自定義方法了,接下來的問題就是這個方法到底是屬于主機的,還是屬于eip的還是兩個資源都需要加一個同樣的方法?而且API的設(shè)計也會影響實現(xiàn)的思路,在設(shè)計時API是把主機和eip當(dāng)成獨立的資源,那么實現(xiàn)的時候很可能就忽略了他們倆之間是有關(guān)聯(lián)關(guān)系的,很可能到最后就會出問題。
4.批量操作變得困難。由于REST API的更新和刪除url路徑都是指向具體一個資源的,批量的更新刪除就需要額外進(jìn)行設(shè)計。比如批量關(guān)閉幾個主機,API的樣子就會和其他的完全不一樣。如果不設(shè)計批量操作的API只是組合使用單個資源的API,當(dāng)需要操作的實例多的時候很容易出現(xiàn)性能問題,而且如果操作時間過長,那么中間各種沖突,不一致的幾率就會大幅上升。
Google的應(yīng)對方案
1.層級多的問題,翻一下google cloud的api可以發(fā)現(xiàn)大部分的api url只有三層,前兩層還都是project和zone,一個實例的url就是/v1/projects/project/zones/zone/instances/instance換句話說就是真正到了云里面的資源就沒有再分層了,所有的資源層級都是扁平的在同等地位,所有的資源都是關(guān)聯(lián)關(guān)系而不是層級關(guān)系。這樣就避免了層級過深和考慮如何設(shè)計層級的問題,也保證了將來每個資源操作的靈活性。
2.大量的自定義方法。盡管REST本來的目的是大量的資源少量的標(biāo)準(zhǔn)操作,很顯然這個顯示環(huán)境中是有困難的。Google在instance這個資源的自定義方法就有20多種,最后的情況就是大量的資源加上幾個標(biāo)準(zhǔn)方法再加上大量的自定義方法。通過自定義方法,每個方法對應(yīng)一個操作,權(quán)限控制也可以對應(yīng)到每一個方法上,細(xì)粒度的權(quán)限控制也就可以實現(xiàn)。
3.HTTP BATCH方法。至于批量操作的問題Google是通過自定義HTTP方法實現(xiàn)的,之前說過了不要用自定義HTTP方法因為大家不支持,可是Google這種能對Web標(biāo)準(zhǔn)起到影響的企業(yè)就任性了。BATCH方法其實就是在HTTP的body里再封裝多個標(biāo)準(zhǔn)的HTTP方法求情。這樣批量操作還是一個個的操作,不過可以一次性打包發(fā)過去不用一個個發(fā)快遞了。API也不用單獨再設(shè)計一套批量的,還能組合不同類型的操作,不過一般企業(yè)就不要學(xué)這種作風(fēng)了。
盡管Google很詳細(xì)的做了API設(shè)計的文檔,但是如果你去看國內(nèi)IaaS廠商的API文檔會發(fā)現(xiàn)沒有一家是這么做的,甚至連一點REST的模樣都沒有。Google的API設(shè)計看上去最符合開發(fā)者的常規(guī)思維,在這個領(lǐng)域反而顯得和一個另類一樣,為啥子呢?如果你看過AWS的API就會發(fā)現(xiàn)國內(nèi)這些廠商大概都是從AWS那邊借(chao)鑒(xi)過來的。至于AWS是如何應(yīng)對REST世界中的類似問題以及他到底長什么樣子,可能下篇會寫。
特別聲明:以上文章內(nèi)容僅代表作者本人觀點,不代表ESG跨境電商觀點或立場。如有關(guān)于作品內(nèi)容、版權(quán)或其它問題請于作品發(fā)表后的30日內(nèi)與ESG跨境電商聯(lián)系。
二維碼加載中...
使用微信掃一掃登錄
使用賬號密碼登錄
平臺顧問
微信掃一掃
馬上聯(lián)系在線顧問
小程序
ESG跨境小程序
手機入駐更便捷
返回頂部