新聞中心
晚上,RESTful發(fā)明人羅伊悄悄來(lái)到了咖啡館,他想看看自己引以為傲的RESTful到底用得怎么樣。

(RESTful的故事參見(jiàn)《RPC發(fā)展簡(jiǎn)史》)
靠著門(mén)的那張桌子有一幫人,他們居然還在討論老掉牙的Java RMI,似乎遇到了什么技術(shù)難題。
看來(lái)無(wú)論是什么技術(shù),都會(huì)有非常古老的遺留系統(tǒng)需要維護(hù),真是苦逼的程序員啊, 羅伊感慨。
這邊的一群人在討論Google的Protobuf , 看來(lái)在序列化這一塊兒已經(jīng)有了長(zhǎng)足的進(jìn)展,都可以實(shí)現(xiàn)跨語(yǔ)言序列化了。
再往里邊走,終于有人討論RESTful了! 羅伊心中一陣激動(dòng)。
只聽(tīng)到一個(gè)人說(shuō)道:“我們領(lǐng)導(dǎo)剛開(kāi)始強(qiáng)制用RESTful的面向資源的風(fēng)格,大家還挺新奇的,可是用著用著,我們就‘退回’到那種面向函數(shù)的方式了?!?/p>
“是啊是啊,我還是更習(xí)慣傳統(tǒng)的RPC方式,更加直觀,尤其是用了Dubbo以后,面向函數(shù)的風(fēng)格不要太爽。”
羅伊心中有點(diǎn)失望。
RESTful的硬傷
“其實(shí)吧,RESTful有個(gè)硬傷,你們發(fā)現(xiàn)沒(méi)有?” 有個(gè)叫做格拉夫的人突然來(lái)了一句。
“什么硬傷?”
“我給你們舉個(gè)例子,” 格拉夫說(shuō)道,“比如我有兩個(gè)資源,一個(gè)叫做Article ,一個(gè)叫做User?!?/p>
“這很正常啊,對(duì)資源可以增刪改查?!?羅伊說(shuō)道,他的話也引起了周?chē)说母胶汀?/p>
“聽(tīng)我說(shuō)完,我現(xiàn)在要開(kāi)發(fā)一個(gè)手機(jī)端,要展示一個(gè)文章的列表,假設(shè)界面原型是這個(gè)樣子:”
“***步,我需要獲得這些文章列表,可以這么做 GET /articles ”
“這也沒(méi)問(wèn)題啊!不就是一個(gè)普通的獲取資源表示的方式嗎?” 人群中有人說(shuō)道。
可是羅伊敏銳地發(fā)現(xiàn),界面中需要一個(gè)“作者頭像”, 很明顯,這個(gè)作者頭像并不在Article這個(gè)資源中保存, 而是在User中。
在返回的結(jié)果中只有author_id, 如果想要獲得作者頭像,需要對(duì)返回的文章列表做循環(huán),取出author_id ,然后在通過(guò)/users這個(gè)資源進(jìn)行查詢。
當(dāng)羅伊把這個(gè)查詢展示出來(lái)以后,周?chē)巳壕驼隋仯骸坝卸嗌賯€(gè)文章,就額外發(fā)出多少次查詢,這怎么行?! 實(shí)際中肯定不能這么干!”
還有人說(shuō):“我們僅僅需要頭像信息(avatar_url),你返回這么多亂七八糟的gender, age,last_login_time干嘛! ”
“這RESTful真是糟糕啊!”
羅伊有點(diǎn)尬尷,沒(méi)想到我的RESTful會(huì)存在這么兩個(gè)問(wèn)題:
1. 發(fā)送請(qǐng)求過(guò)多 (對(duì)每個(gè)文章,都得額外查詢作者信息)
2. 太多的額外信息(其實(shí)只想要avatar_url這個(gè)字段)
想到此處,羅伊的心一下子就沉了下去,怎么解決這個(gè)問(wèn)題呢?
中間層
老祖宗教導(dǎo)我們: 計(jì)算機(jī)科學(xué)領(lǐng)域的任何問(wèn)題都可以通過(guò)增加一個(gè)間接的中間層來(lái)解決!
這個(gè)中間層是什么? 羅伊想到了前后端還沒(méi)有分離的時(shí)候,頁(yè)面都是在后端渲染的,程序員會(huì)創(chuàng)建一個(gè)VO(View Object),在這個(gè)VO中,會(huì)把界面展示所需要的信息都封裝起來(lái),然后再發(fā)給JSP去使用。
在RESTful當(dāng)中,也可以搞一個(gè)類似VO的資源出來(lái)啊, 想到此處,他對(duì)格拉夫說(shuō)道:“你為什么不搞一個(gè)HotArticle這樣的資源出來(lái)呢? ”
這個(gè)HotArticle可以把文章和作者做個(gè)組合,只返回那些界面需要的數(shù)據(jù)。
格拉夫說(shuō)道:“這樣可不好, 這個(gè)HotArticle資源相當(dāng)于和界面深度綁定了。界面如果要變化,這個(gè)HotArticle也得變化,很麻煩啊?!?/p>
羅伊說(shuō):“那就一起變化唄,反正兩個(gè)是一致的?!?/p>
“不,還有更復(fù)雜的情況, 假設(shè)界面發(fā)生了變化,需要把作者頭像替換成文章的封面圖, 這時(shí)候怎么辦呢?”
羅伊說(shuō):“我明白你的意思,不就是說(shuō)要同時(shí)支持老的手機(jī)端和新的手機(jī)端嗎?簡(jiǎn)單,有兩種方案?!?/p>
(1) 復(fù)用HotArticle, 保留原來(lái)的avatar_url, 添加一個(gè)新的字段 article_img_url, 不同的手機(jī)端各取所需。
(2) 給HotArticle做個(gè)新版本。老的手機(jī)端用老版本,新的手機(jī)端用新版本。
“***種方案好!很簡(jiǎn)單!” 人群中有人說(shuō)道。
“好啥啊,如果手機(jī)界面持續(xù)變化,你用***種辦法,那個(gè)HotArticle很快就成了垃圾堆了,要是沒(méi)有準(zhǔn)確無(wú)誤的文檔,都不知道哪個(gè)字段被誰(shuí)使用!”
“第二種方案會(huì)搞出很多版本來(lái),假設(shè)要改個(gè)公共的東西,比如要增加一個(gè)文章的閱讀數(shù),那豈不是所有的都得改? ”
可見(jiàn)兩種辦法各有優(yōu)劣, 在應(yīng)對(duì)手機(jī)端界面持續(xù)變化時(shí)都有問(wèn)題,都不***。這也是后端資源和前端界面綁定后的惡果啊。
靈活查詢
羅伊陷入了沉思: 能不能讓手機(jī)端按需查詢呢?
服務(wù)器端保持最簡(jiǎn)單的Article 和 User的概念,把他們看成兩張表,手機(jī)端發(fā)出像SQL 那樣的查詢,把自己需要的給查出來(lái),***能類似于Join的功能。
想到此處,他就寫(xiě)了這么一個(gè)SQL :
select a.id, a.title, a.abstract, a.liked_count, u.avatar_url from Article a , User u where a.author_id = u.id
看到這個(gè)圖,人群轟然叫好:“還是SQL大法好!”
只有格拉夫冷冷地說(shuō)道:“SQL的局限性太大, 比如我還要把作者的朋友同時(shí)顯示到手機(jī)端,這SQL就不好寫(xiě)了,文章和作者是一一對(duì)應(yīng)的,但是作者的朋友可能有多個(gè),這樣SQL的結(jié)果集中就會(huì)有重復(fù)的文章id , title , abstract了?!?/p>
羅伊說(shuō):“那你說(shuō)怎么辦?”
“關(guān)系模型在表示這樣的關(guān)聯(lián)的時(shí)候,非常不方便,我發(fā)明了一個(gè)新的模型和新的查詢語(yǔ)言, 大家看看吧?!?/p>
古怪的查詢
格拉夫展示了一個(gè)查詢的方法:
大家猛地一看, 這個(gè)查詢太古怪了啊,這是什么語(yǔ)法?
雖然古怪,卻非常實(shí)用,精確地描述了這個(gè)需求:我需要一個(gè)id 為11的用戶, 把他的name, age, avatar_url等字段給我取過(guò)來(lái),其他字段就不用發(fā)過(guò)來(lái)了。
查詢結(jié)果也是標(biāo)準(zhǔn)的JSON格式,和要查詢的內(nèi)容一一對(duì)應(yīng),非常容易理解。
羅伊問(wèn)道:“這也沒(méi)啥啊,你怎么解決之前的問(wèn)題?”
格拉夫又展示了一個(gè)查詢,這一次復(fù)雜了一些:
“看到?jīng)]有? 這次表示一個(gè)article列表,每個(gè)article元素里邊有id, title, abstract,liked_count等字段。 還有一個(gè)特殊字段叫做author,相當(dāng)于在article中嵌套了一個(gè)元素,這個(gè)author元素還有一個(gè)字段叫做avatar_url。 ”
眾人一看,覺(jué)得非常有意思,用這種方式***地解決了之前的問(wèn)題。
只需要一次查詢,文章和作者的頭像一起就發(fā)回來(lái)了,更重要的是,沒(méi)有什么亂七八糟的額外信息。
如果想加上作者的朋友信息,可以把查詢改成下面這個(gè)樣子,非常靈活。
看到此處,羅伊就明白了幾分,這是一種新的查詢方式,不同于關(guān)系數(shù)據(jù)庫(kù)的SQL, 也不同于RESTful, 很明顯,后端的數(shù)據(jù)模型也得發(fā)生變化。
他問(wèn)道:“你后端的數(shù)據(jù)模型難道是圖Graph嗎?”
格拉夫贊道:“被你看出來(lái)了,真是厲害,為了支持這樣的查詢,在后臺(tái)的數(shù)據(jù)模型就是一張圖:”
“根據(jù)這張圖,我就可以查找出任意的數(shù)據(jù)了,從Article找到作者, 從作者找到相關(guān)的朋友......, 只要你把關(guān)聯(lián)做好,沒(méi)有什么做不到的。”
“那些Article, User類型及其屬性是不是也得明確地定義下來(lái)?” 羅伊又問(wèn)道。
格拉夫?qū)α_伊投去贊嘆的目光, 說(shuō)道:“沒(méi)錯(cuò),可以這么定義?!?/p>
一目了然,大家都非常喜歡!
“這個(gè)新的查詢語(yǔ)言叫什么名字?”
“我叫格拉夫(Graph),所以這個(gè)查詢語(yǔ)言叫做GraphQL!”
【本文為專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)作者微信公眾號(hào)coderising獲取授權(quán)】
戳這里,看該作者更多好文
標(biāo)題名稱:為什么RESTful很糟糕?
當(dāng)前地址:http://fisionsoft.com.cn/article/codhhsp.html


咨詢
建站咨詢
