官术网_书友最值得收藏!

4.3.1 GraphQL與RESTful API

假設(shè)正在開(kāi)發(fā)一個(gè)Web應(yīng)用程序,讓我們先來(lái)回想日常開(kāi)發(fā)過(guò)程中的真實(shí)場(chǎng)景:服務(wù)端開(kāi)發(fā)人員通過(guò)HTTP暴露了一個(gè)RESTful API,然后前端開(kāi)發(fā)人員嘗試對(duì)這個(gè)HTTP端點(diǎn)發(fā)起調(diào)用。這個(gè)HTTP端點(diǎn)一開(kāi)始如代碼清單4-56所示。

代碼清單4-56 普通HTTP端點(diǎn)示例代碼

請(qǐng)求:
GET  https://api.example.com/user/1
響應(yīng):
{
    "id": "1",
    "name": "tianyalan",
    "age": "38",
    "address": "shanghai"
}

看上去非常簡(jiǎn)單,對(duì)不對(duì)?剛開(kāi)始前后端聯(lián)調(diào)一切正常。不知什么時(shí)候,前端開(kāi)發(fā)人員發(fā)現(xiàn)響應(yīng)結(jié)果中原來(lái)的address字段不見(jiàn)了,而是出現(xiàn)了一個(gè)location字段,原來(lái)是后端開(kāi)發(fā)人員覺(jué)得address這個(gè)字段名不合適,偷偷把它改成了location,但并沒(méi)有告訴前端開(kāi)發(fā)人員。圖4-5展示了這一過(guò)程。這時(shí)候,前后端之間就需要重新明確API定義,并再一次進(jìn)行聯(lián)調(diào)。顯然,這個(gè)過(guò)程實(shí)際上是非常浪費(fèi)時(shí)間的。

106-1

圖4-5 Web API中字段名變更示意圖

相信你對(duì)上面這個(gè)場(chǎng)景非常熟悉,因?yàn)槲覀兛赡苊刻於荚诜磸?fù)經(jīng)歷著類似的場(chǎng)景。從這些場(chǎng)景中,前后端開(kāi)發(fā)人員已經(jīng)意識(shí)到,傳統(tǒng)的RESTful API并不能非常好地滿足前后端分離場(chǎng)景下的交互需求。我們可以進(jìn)一步把RESTful API存在的問(wèn)題做一些梳理。

1. RESTful API存在的問(wèn)題

RESTful API的第一個(gè)典型問(wèn)題就是前端無(wú)法預(yù)判響應(yīng)的數(shù)據(jù)格式,正如圖4-5所展示的那樣,一旦服務(wù)端對(duì)數(shù)據(jù)結(jié)構(gòu)做了任何改變,前端都只能被動(dòng)接收,而無(wú)法在發(fā)起請(qǐng)求之前感知到這種改變。

RESTful API的第二個(gè)典型問(wèn)題是無(wú)法根據(jù)請(qǐng)求控制對(duì)應(yīng)的返回結(jié)果。例如在圖4-5的場(chǎng)景中,前端請(qǐng)求可能只想獲取User對(duì)象中的name和age字段,而不需要address字段。顯然,RESTful API無(wú)法滿足這種訴求,除非另外開(kāi)發(fā)一個(gè)HTTP端點(diǎn)。我們知道,數(shù)據(jù)在網(wǎng)絡(luò)中的傳輸是需要成本的,無(wú)法按需獲取數(shù)據(jù)同樣導(dǎo)致了資源的不必要浪費(fèi)。

RESTful API的第三個(gè)典型問(wèn)題就是多次請(qǐng)求。再次回到上述場(chǎng)景中,假設(shè)User對(duì)象中包含了一組家庭成員信息。那么基于RESTful API,如果想要獲取這些數(shù)據(jù),就只能再發(fā)起一個(gè)專門的請(qǐng)求來(lái)根據(jù)User的id獲取對(duì)應(yīng)的家庭成員列表,例如圖4-6中所展示的https://api.example.com/user/family/1

107-1

圖4-6 RESTful API的多次請(qǐng)求示意圖

當(dāng)然,我們也可以針對(duì)該需求專門設(shè)計(jì)一個(gè)能夠同時(shí)返回用戶信息和家庭成員信息的接口。但這又會(huì)引出RESTful API的第四個(gè)典型問(wèn)題,即請(qǐng)求地址過(guò)多的問(wèn)題。如果針對(duì)各個(gè)具體場(chǎng)景我們都需要一一暴露專門的HTTP端點(diǎn),那么在一個(gè)系統(tǒng)中HTTP端點(diǎn)數(shù)量會(huì)非常龐大,難以維護(hù)和管理。

RESTful API的問(wèn)題已經(jīng)暴露得非常清楚了。如何有效解決這些問(wèn)題呢?可以引入一個(gè)新技術(shù),即GraphQL。

相比于REST,GraphQL可以說(shuō)是一個(gè)比較新的技術(shù),它于2012年誕生在Facebook內(nèi)部,并于2015年正式開(kāi)源。顧名思義,GraphQL是一種基于圖(Graph)的查詢語(yǔ)言(Query Language,QL),從根本上改變了前后端交互API的定義和實(shí)現(xiàn)方式。接下來(lái),我們?cè)敿?xì)分析如何通過(guò)GraphQL解決RESTful API所面臨的一系列問(wèn)題。

2. GraphQL的解決方案

要想使用GraphQL,我們首先需要關(guān)注它發(fā)送請(qǐng)求的方式。針對(duì)獲取用戶信息這個(gè)場(chǎng)景,一個(gè)典型的請(qǐng)求示例如代碼清單4-57所示。

代碼清單4-57 基于GraphQL的請(qǐng)求示例代碼

{
    user (id: "1") {
        name
        age
    }
}

可以看到基于GraphQL的請(qǐng)求方式與使用RESTful API有很大的不同。除了在請(qǐng)求體中指定了目標(biāo)User對(duì)象的參數(shù)id值之外,我們還額外指定了name和age這兩個(gè)參數(shù),也就是告訴服務(wù)器端這次請(qǐng)求所希望獲取的數(shù)據(jù)字段。

顯然,這種請(qǐng)求方式完美解決了RESTful API中無(wú)法根據(jù)請(qǐng)求控制對(duì)應(yīng)返回結(jié)果的問(wèn)題。同時(shí),這種請(qǐng)求方式也解決了前端無(wú)法預(yù)判響應(yīng)的數(shù)據(jù)的格式問(wèn)題,因?yàn)榍岸嗽谡?qǐng)求的同時(shí)已經(jīng)知道從服務(wù)端返回的數(shù)據(jù)字段就是請(qǐng)求中指定的字段,因此就不需要再對(duì)響應(yīng)結(jié)果進(jìn)行專門的判斷和處理。

針對(duì)RESTful API存在的多次請(qǐng)求問(wèn)題,GraphQL可以把多次請(qǐng)求合并成一次。例如,我們可以發(fā)送如代碼清單4-58所示的請(qǐng)求。

代碼清單4-58 基于GraphQL的合并多次請(qǐng)求示例代碼

{
    users {
        name
        age
        members {
            name
        }
    }
}

在該請(qǐng)求中,我們指定了想要獲取的User對(duì)象中的name和age字段,同時(shí)也指定了該獲取用戶對(duì)應(yīng)的家庭成員列表字段members以及它的子字段name。這樣,通過(guò)一次請(qǐng)求,我們就可以同時(shí)獲取用戶信息和家庭成員信息,而不需要像RESTful API那樣發(fā)送兩次請(qǐng)求。

講到這里,你可能已經(jīng)注意到,通過(guò)GraphQL發(fā)起請(qǐng)求實(shí)際上只需要指定一個(gè)HTTP端點(diǎn)地址即可,因?yàn)槲覀兛梢曰谕粋€(gè)端點(diǎn)傳入不同的參數(shù)而獲取不同的結(jié)果,也就不需要專門設(shè)計(jì)一批HTTP端點(diǎn)來(lái)分別處理不同的請(qǐng)求了。

總結(jié)一下,RESTful API所存在的核心問(wèn)題通過(guò)GraphQL都可以得到解決。

主站蜘蛛池模板: 新干县| 巴里| 卓尼县| 武宁县| 宜君县| 泸定县| 浮山县| 应用必备| 阿城市| 揭阳市| 正阳县| 河源市| 紫金县| 天津市| 芒康县| 黄龙县| 玉田县| 齐河县| 烟台市| 乐清市| 鹿邑县| 奎屯市| 石泉县| 潼南县| 宁波市| 当雄县| 安新县| 昌宁县| 西丰县| 驻马店市| 兰西县| 施秉县| 海门市| 潼南县| 临澧县| 湄潭县| 兖州市| 西昌市| 通州区| 北川| 丹东市|