定义资源
在Fielding的論文中 ,資源被描述為:
“可以命名的任何信息”……“文檔或圖像,臨時(shí)服務(wù)(例如,“洛杉磯今天的天氣”),其他資源的集合,非虛擬對(duì)象(例如,人) 等等。 換句話說(shuō),任何可能成為作者超文本 引用 目標(biāo)的概念都 必須符合資源的定義。 資源是 到一組實(shí)體 的概念性映射 ,而不是在任何特定 時(shí)間 點(diǎn)對(duì)應(yīng)于該映射的實(shí)體 ?!?
定義資源既是科學(xué)也是藝術(shù) 。 它需要領(lǐng)域知識(shí)和API體系結(jié)構(gòu)技能。 下面詳細(xì)介紹的以下幾點(diǎn)用作清單,可以幫助您確定資源。
資源必須包含業(yè)務(wù)說(shuō)明
- 商業(yè)描述應(yīng)為簡(jiǎn)單散文中的3-4個(gè)句子,以說(shuō)明資源是什么。
- 對(duì)您的系統(tǒng)有一定了解的開(kāi)發(fā)人員應(yīng)該能夠理解該描述
- 資源的任何警告均應(yīng)明確
資源應(yīng)單獨(dú)使用
這類(lèi)似于定義微服務(wù)邊界的準(zhǔn)則,在這種情況下,應(yīng)將微服務(wù)視為自身有用。 同樣,資源應(yīng)單獨(dú)使用。
例如,代替:
/street-address/{id} RESPONSE { "street1" : "String" , "street2" : "String" }和
/address-extra/{id} RESPONSE { "city" : "String" , "country" : "String" }它應(yīng)該是:
/address/{id} RESPONSE { "street1" : "String" , "street2" : "String" , "city" : "String" , "country" : "String" }如果資源本身沒(méi)有用,并且總是需要后續(xù)請(qǐng)求,則意味著代碼將不可避免地變得更加復(fù)雜,并且第二個(gè)請(qǐng)求將對(duì)性能造成影響
使用適當(dāng)?shù)拿~
最好使用簡(jiǎn)單名詞而不是復(fù)合名詞。 例如,
地址優(yōu)于AddressInfo或AddressDetail 。 這是一條一般規(guī)則,總會(huì)有例外 。
如果使用多個(gè)資源表示同一數(shù)據(jù)的不同視圖,例如: Address和AddressDetail ,則使用簡(jiǎn)單名詞,例如
地址第一。 然后,如果第二種表示形式更詳細(xì)地使用
ResourceNameDetail,或者如果不夠詳細(xì),請(qǐng)使用ResourceNameSummary 。 例如,假設(shè)需要引入一個(gè)地址類(lèi)型資源:
如果僅在READ中使用它,它是否需要成為資源?
如果僅在讀取請(qǐng)求中使用過(guò)資源,而從未在寫(xiě)入 ( 創(chuàng)建,部分更新,完全更新,刪除等 )請(qǐng)求中使用過(guò)資源,則是否需要將其定義為具有自己的URI的資源是可疑的。 可以將其添加到父負(fù)載中,如果擔(dān)心負(fù)載會(huì)變得太復(fù)雜,則父可以僅提供一個(gè)稀疏查詢-客戶端可以根據(jù)API請(qǐng)求確定要返回的內(nèi)容。
資源應(yīng)符合統(tǒng)一接口
統(tǒng)一的接口是良好API設(shè)計(jì)的重要組成部分。 如果創(chuàng)建,讀取,更新,刪除等操作以一致的方式進(jìn)行,則意味著代碼更加一致,可重用且更易于維護(hù)。
這表示:
GET /addresses/{id}和
GET /addresses必須返回相同的地址數(shù)據(jù)結(jié)構(gòu)來(lái)表示一個(gè)地址。
GET /addresses/{id} RESPONSE { "id" : "546" , "street1" : "String" , "street2" : "String" , "city" : "String" , "country" : "String" }和
GET /addresses RESPONSE { "elements" : [ { "id" : "546" , "street1" : "String" , "street2" : "String" , "city" : "String" , "country" : "String" }, ... ] }同樣,對(duì)于寫(xiě)入有效負(fù)載,數(shù)據(jù)結(jié)構(gòu)應(yīng)該相同。 因此,更改street1的部分更新將是:
POST /addresses/{id}/edit REQUEST { "street1" : "Walkview" } RESPONSE { "id" : "546" , "street1" : "Walkview" , "street2" : "Meadowbrook" , "city" : "Dublin" , "country" : "Ireland" }而不是像
POST /addresses/{id} REQUEST { "newStreet1Value" : "Walkview" }從資源的角度來(lái)看,數(shù)據(jù)結(jié)構(gòu)必須一致。 不同的數(shù)據(jù)結(jié)構(gòu)意味著不同的資源,應(yīng)使用不同的名稱(chēng)命名并具有自己的路徑。
不要暴露一切
如果您的數(shù)據(jù)庫(kù)模型非常復(fù)雜,則不需要在API級(jí)別公開(kāi)所有屬性。 有些字段只能保留用于后臺(tái)處理,而不能顯示在UI上。 此類(lèi)屬性永遠(yuǎn)不應(yīng)包含在JSON API中。
在將屬性添加到JSON資源時(shí),請(qǐng)考慮:
- API中應(yīng)僅公開(kāi)您確定客戶端感興趣的字段
- 如果不確定,請(qǐng)忽略該屬性。 稍后添加屬性,然后刪除已經(jīng)公開(kāi)的屬性的風(fēng)險(xiǎn)要低得多。
API模型不應(yīng)盲目地反映數(shù)據(jù)庫(kù)關(guān)系模型或OO模型
在數(shù)據(jù)庫(kù)建模方法中,使用規(guī)范化數(shù)據(jù)或折疊繼承層次結(jié)構(gòu)。 在面向?qū)ο蟮脑O(shè)計(jì)中,諸如多態(tài),繼承層次結(jié)構(gòu)等技術(shù)被用于促進(jìn)諸如代碼重用之類(lèi)的事情并減少耦合。
資源建模不必遵循這些技術(shù)。 API的使用者不關(guān)心數(shù)據(jù)是全部放在一個(gè)表中還是在多個(gè)表中進(jìn)行了規(guī)范化。 通常,API以易于使用的格式返回?cái)?shù)據(jù),并且在客戶端變得有用之前不需要客戶端進(jìn)行太多其他映射。
使用分層數(shù)據(jù)避免重復(fù)
與諸如CSV之類(lèi)的平面格式相比,分層數(shù)據(jù)的優(yōu)點(diǎn)之一是它提供了一種避免重復(fù)的機(jī)制。 例如,考慮一個(gè)數(shù)據(jù)結(jié)構(gòu),其中包含人員列表以及他們所在的團(tuán)隊(duì)。在CSV中,這是:
team, firstname, lastname Liverpool, Mo, Salah Liverpool, Andy, Roberston在JSON中,可能是:
{ "team" : "Liverpool" , "players" : [ { "firstName" : "Mo" , "lastName" : "Salah" }, { "firstName" : "Andy" , "lastName" : "Roberston" }, ... ] }使用分層數(shù)據(jù)使上下文清晰
分層數(shù)據(jù)的另一個(gè)優(yōu)點(diǎn)是它有助于提供上下文。 要了解平面數(shù)據(jù)結(jié)構(gòu),您需要了解生成數(shù)據(jù)結(jié)構(gòu)的查詢是什么,以了解其含義。 例如,考慮一堆包含日期范圍的行。
name, fromDate, toDate, holidays Tony, 2018 - 01 - 01 , 2018 - 02 - 02 , true Tony, 2018 - 02 - 03 , 2018 - 03 - 01 , false您可以假設(shè)當(dāng)Tony休假時(shí)會(huì)有新的一行。 但是如果還有另一列怎么辦
name, fromDate, toDate, holidays, sick, Tony, 2018 - 01 - 01 , 2018 - 02 - 02 , true , false Tony, 2018 - 02 - 03 , 2018 - 03 - 01 , false , true日期范圍是否對(duì)應(yīng)于假期,疾病或兩者兼而有之?
如果我們能獲得更多數(shù)據(jù),也許會(huì)更清楚……
name, fromDate, toDate, holidays, sick, Tony, 2018 - 01 - 01 , 2018 - 02 - 02 , true , false Tony, 2018 - 02 - 03 , 2018 - 03 - 01 , false , true Tony, 2018 - 03 - 02 , 2018 - 04 - 01 , false , false現(xiàn)在看來(lái),日期范圍所對(duì)應(yīng)的是一種病,這只是一個(gè)巧合,它排列了一個(gè)假期。 但是,當(dāng)我們獲得更多數(shù)據(jù)時(shí),此理論將失敗:
name, fromDate, toDate, holidays, sick, Tony, 2018 - 01 - 01 , 2018 - 02 - 02 , true , false Tony, 2018 - 02 - 03 , 2018 - 03 - 01 , false , true Tony, 2018 - 03 - 02 , 2018 - 04 - 01 , false , false Tony, 2018 - 04 - 02 , 2018 - 05 - 01 , true , false平面數(shù)據(jù)結(jié)構(gòu)的問(wèn)題在于,只能使數(shù)據(jù)自我描述。 如果沒(méi)有任何信息,它將變得更加復(fù)雜。 例如:
name, fromDate, toDate, holidays, sick, Tony, 2018 - 01 - 01 , 2018 - 02 - 02 , true , false Tony, 2018 - 02 - 03 , 2018 - 03 - 01 , false , true Tony, 2018 - 03 - 02 , 2018 - 04 - 01 , false , false Tony, 2018 - 04 - 02 , 2018 - 05 - 01 , true , false Tony, 2018 - 05 - 02 , 2018 - 06 - 01 , null , false Tony, 2018 - 06 - 02 , 2018 - 07 - 01 , null , false Tony, 2018 - 07 - 02 , 2018 - 07 - 08 , true , false Tony, 2018 - 07 - 08 , 2018 - 07 - 09 , true , null不可避免的是,處理該數(shù)據(jù)將是錯(cuò)誤的。 我們可以用以下分層格式表示相同的數(shù)據(jù):
{ "name" : "tony" , "holidays" : [ { "fromDate" : "fromDate" "2018-01-01" , "toDate" : "2018-02-02" }, { "fromDate" : "fromDate" "2018-04-02" , "toDate" : "2018-05-01" }, { "fromDate" : "2018-07-02" , "toDate" : "2018-07-09" } ], "sick" : [ { "fromDate" : "2018-02-03" , "toDate" : "2018-03-01" } ] }現(xiàn)在,數(shù)據(jù)更加自我描述。 很清楚,日期范圍是假期還是病假。
資源關(guān)系
資源本身只能描述自己。 資源模型描述資源之間的關(guān)系。 這將表明:
- 資源之間的依賴關(guān)系。 存在特定資源需要哪些資源,或者當(dāng)特定資源發(fā)生更改時(shí)會(huì)影響哪些資源:更新或刪除。
- 數(shù)據(jù)導(dǎo)航–在大域模型中,如果向模型的使用者提供導(dǎo)航和方向感,則更容易理解和遵循。 尤其是何時(shí)進(jìn)行導(dǎo)航(資源松散連接)與向下導(dǎo)航(資源牢固連接)可以區(qū)分開(kāi)
資源不僅應(yīng)該考慮實(shí)現(xiàn)HATEOAS的超媒體鏈接; 當(dāng)資源使用超媒體鏈接描述它們所鏈接的內(nèi)容時(shí),它是表達(dá)資源模型的一種非常強(qiáng)大的機(jī)制。 優(yōu)勢(shì)包括:
- 它將大型域模型分成更易于管理的部分。 通常,用戶只對(duì)模型的特定部分感興趣。 當(dāng)“資源”自己描述自己的關(guān)系時(shí),這意味著將一個(gè)大型的復(fù)雜模型分解為易于消化的部分,并且用戶可以更快地獲取所需的信息。
- 資源模型是自我描述的,并與代碼保持同步。 一切都在同一地點(diǎn)。
明確父母與子女的關(guān)系
子級(jí)自我描述了父級(jí)URL層次名稱(chēng)間距。 父資源具有一種或多種類(lèi)型的子代,應(yīng)通過(guò)提供指向子代的鏈接來(lái)闡明這一點(diǎn)。 例如,如果一個(gè)團(tuán)隊(duì)有一個(gè)玩家。 團(tuán)隊(duì)有效負(fù)載應(yīng)對(duì)此進(jìn)行明確說(shuō)明。
明確對(duì)等關(guān)系
這與上面的類(lèi)似,只不過(guò)它用于存在于不同層次名稱(chēng)空間中的資源。 因此,例如,假設(shè)團(tuán)隊(duì)在部門(mén)1中。應(yīng)該在團(tuán)隊(duì)的部門(mén)屬性中包含一個(gè)鏈接。
REQUEST https: //api.server.com/teams/4676 RESPONSE { "id" : "34533" , "division" : { "name" : "Division 1" , "_links" : { "self" : " https://api.server.com/divisions/1 " } }, ..., "_links" : { "self" : " https://api.server.com/teams/4676 " , "players" : " https://api.server.com/teams/4676/players " } }明確鏈接到其他表示形式
如果將數(shù)據(jù)建模為具有多個(gè)代表數(shù)據(jù)不同表示形式的資源,則這些資源還應(yīng)包括彼此的鏈接。
REQUEST https: //api.server.com/teams/4676 RESPONSE { "id" : "34533" , "division" : { "name" : "Division 1" , "_links" : { "self" : " https://api.server.com/divisions/1 " } }, ..., "_links" : { "self" : " https://api.server.com/teams/4676 " , "players" : " https://api.server.com/teams/4676/players " , "teamDetails" : " https://api.server.com/teamDetails/4676 " } }翻譯自: https://www.javacodegeeks.com/2019/06/defining-resource.html
總結(jié)
- 上一篇: iPhone 15国行版相比美版原来&l
- 下一篇: 关于“最终”的最终决定