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