Rest相比GraphQL有什么好處?

2021-03-13    分類: 網(wǎng)站建設(shè)

兩種通過(guò)HTTP發(fā)送數(shù)據(jù)的方式:有什么區(qū)別?

通常情況下,GraphQL被視作一種革命性的對(duì)于API查詢方式的思考,您可以發(fā)送查詢,以便在一個(gè)請(qǐng)求中準(zhǔn)確獲取要查找的數(shù)據(jù),而無(wú)需使用嚴(yán)格的服務(wù)器端定義。事實(shí)確實(shí)如此 - 當(dāng)組織采用GraphQL時(shí),它可以具有變革性,使前端和后端團(tuán)隊(duì)能夠比以前更順利地進(jìn)行協(xié)作。 但實(shí)際上,這兩種技術(shù)都涉及發(fā)送HTTP請(qǐng)求并接收一些結(jié)果,并且GraphQL包含許多內(nèi)置的REST模型元素。

那么技術(shù)層面上真正發(fā)生了什么? 這兩個(gè)API范例有什么相似之處和不同之處? 本文末尾的聲明是,GraphQL和REST其實(shí)沒(méi)有太大的不同,但是GraphQL有一些小的改變,這對(duì)開發(fā)者構(gòu)建和使用API的體驗(yàn)產(chǎn)生了很大的影響。

因此,讓我們直接進(jìn)入。我們將定義一些API屬性,然后討論GraphQL和REST如何處理它們。

資源

REST的核心思想是資源。 每個(gè)資源都由一個(gè)URL標(biāo)識(shí),并通過(guò)向該URL發(fā)送GET請(qǐng)求來(lái)檢索該資源。 你可能會(huì)得到一個(gè)JSON響應(yīng),因?yàn)檫@是大多數(shù)API現(xiàn)在使用的。 所以它看起來(lái)像這樣:

GET /books/1
{ "title": "Black Hole Blues", "author": {   "firstName": "Janna",  "lastName": "Levin" } // ... more fields here}

Note: 在上面的示例中,一些REST API會(huì)將“author”作為單獨(dú)的資源返回.

在REST中需要注意的一點(diǎn)是,資源的類型或形狀以及您獲取資源的方式是耦合的。 當(dāng)您在REST文檔中討論上述內(nèi)容時(shí),您可能會(huì)將其稱為“book endpoint”.

GraphQL在這方面完全不同,因?yàn)樵贕raphQL中,這兩個(gè)概念是完全分離的。 在您的模式中,您可能有Book和Author類型:

type Book { id: ID title: String published: Date price: String author: Author}
type Author { id: ID firstName: String lastName: String books: [Book]}

請(qǐng)注意,我們所描述的各種數(shù)據(jù)可用,但這種描述不會(huì)告訴你任何關(guān)于如何在客戶端獲取這些對(duì)象。 這是REST和GraphQL的核心區(qū)別 - 特定資源的描述與您檢索它的方式不相關(guān)。

為了能夠?qū)嶋H訪問(wèn)特定的book或author,我們需要在我們的模式中創(chuàng)建一個(gè)Query類型:

type Query { book(id: ID!): Book author(id: ID!): Author}

現(xiàn)在,我們可以發(fā)送類似于上面的REST請(qǐng)求的請(qǐng)求,但是這次使用GraphQL:

GET /graphql?query={ book(id: "1") { title, author { firstName } } }
{ "title": "Black Hole Blues", "author": {  "firstName": "Janna", }}

很好,現(xiàn)在我們到了某一步! 我們可以立即看到有關(guān)GraphQL的一些與REST完全不同的內(nèi)容,即使兩者都可以通過(guò)URL請(qǐng)求,并且兩者都可以返回相同形式的JSON響應(yīng)。

首先,我們可以看到帶有GraphQL查詢的URL指定了我們要求的資源以及我們關(guān)心的是哪些字段。 另外,API的使用者決定,而不是服務(wù)器作者為我們決定需要包含相關(guān)author資源。

但最重要的是,資源的標(biāo)識(shí),book和author的概念,并沒(méi)有與它們被獲取的方式相聯(lián)系。 我們可以通過(guò)許多不同類型的查詢以及不同的字段來(lái)檢索相同的Book。

結(jié)論

我們已經(jīng)確定了一些相似之處和差異:

  • 相同點(diǎn): 兩者都有資源的概念,并可以為這些資源指定ID。
  • 相同點(diǎn): 兩者都可以通過(guò)HTTP GET請(qǐng)求獲取URL。
  • 相同點(diǎn): 兩者都可以在請(qǐng)求中返回JSON數(shù)據(jù)。
  • 不同: 在REST中,您調(diào)用的端點(diǎn)是該對(duì)象的標(biāo)識(shí)。 在GraphQL中,標(biāo)識(shí)與獲取它的方式是分開的.
  • 不同: 在REST中,資源的形狀和大小由服務(wù)器決定。 在GraphQL中,服務(wù)器聲明哪些資源可用,客戶端詢問(wèn)它需要什么。。

好的,如果你已經(jīng)使用了非?;A(chǔ)的GraphQL和/或REST, 如果你之前沒(méi)有使用過(guò)GraphQL,你可以在Launchpad里面玩一玩 an example similar to the above ,Launchpad是一款用于在您的瀏覽器中構(gòu)建和探索GraphQL示例的工具。

URL路由與GraphQL架構(gòu)

如果API不可預(yù)測(cè),則該API無(wú)用。 當(dāng)你使用一個(gè)API時(shí),你通常將它作為某個(gè)程序的一部分來(lái)執(zhí)行,并且該程序需要知道它可以調(diào)用的內(nèi)容以及它應(yīng)該期望得到的結(jié)果,以便它可以運(yùn)行得出結(jié)果。

因此,API中最重要的部分之一是對(duì)可訪問(wèn)內(nèi)容的描述。 這是您在閱讀API文檔時(shí)學(xué)習(xí)的內(nèi)容,以及使用Graphql自檢和Rag API架構(gòu)系統(tǒng)(如Swagger)時(shí),可以通過(guò)編程方式檢查此信息。

在當(dāng)今的REST API中,API通常被描述為一個(gè)端點(diǎn)列表:

GET /books/:idGET /authors/:idGET /books/:id/commentsPOST /books/:id/comments

所以你可以說(shuō)API的“形狀”是線性的 - 有一系列你可以訪問(wèn)的東西。 當(dāng)您檢索數(shù)據(jù)或保存某些內(nèi)容時(shí),首先要問(wèn)的問(wèn)題是“我應(yīng)該調(diào)用哪個(gè)端”?

在GraphQL中,如上所述,您不使用URL來(lái)標(biāo)識(shí)API中可用的內(nèi)容。 相反,您使用GraphQL模式:

type Query { book(id: ID!): Book author(id: ID!): Author}
type Mutation { addComment(input: AddCommentInput): Comment}
type Book { ... }type Author { ... }type Comment { ... }input AddCommentInput { ... }

與類似數(shù)據(jù)集的REST路由相比,這里有一些有趣的地方。 首先,不是將一個(gè)不同的HTTP動(dòng)詞發(fā)送到相同的URL來(lái)區(qū)分讀取和寫入,而是使用不同的 initial type --- Mutation vs. Query。 在GraphQL文檔中,您可以選擇使用關(guān)鍵字發(fā)送哪種類型的操作:

query { ... }mutation { ... }

有關(guān)查詢語(yǔ)言的所有細(xì)節(jié),請(qǐng)閱讀我之前的文章, “GraphQL查詢的解析”

你可以看到Query類型的字段與我們上面的REST路由很好地匹配。 這是因?yàn)檫@種特殊類型是我們數(shù)據(jù)的入口點(diǎn),所以這是GraphQL中與端點(diǎn)URL最相同的概念。

您從GraphQL API獲取初始資源的方式與REST非常相似 - 您傳遞了一個(gè)名稱和一些參數(shù) - 但主要區(qū)別在于您可以從那里開始。 在GraphQL中,您可以發(fā)送一個(gè)復(fù)雜查詢,根據(jù)模式中定義的關(guān)系獲取其他數(shù)據(jù),但在REST中,您必須通過(guò)多個(gè)請(qǐng)求來(lái)完成此操作,將相關(guān)數(shù)據(jù)構(gòu)建到初始響應(yīng)中,或者在 修改響應(yīng)的URL。

結(jié)論

在REST中,可訪問(wèn)數(shù)據(jù)的空間被描述為一個(gè)線性的端點(diǎn)列表,在GraphQL中它是一個(gè)包含關(guān)系的模式。

  • 相同點(diǎn): REST API中的端點(diǎn)列表與GraphQL API中Query和Mutation類型的字段列表類似。 它們都是數(shù)據(jù)的入口點(diǎn)。
  • 相同點(diǎn): 這兩種方法都可以區(qū)分API請(qǐng)求是要讀取數(shù)據(jù)還是寫入數(shù)據(jù)。
  • 不同: 在GraphQL中,您可以在單個(gè)請(qǐng)求中,按照模式中定義的關(guān)系從入口點(diǎn)遍歷相關(guān)數(shù)據(jù)。 在REST中,您必須調(diào)用多個(gè)端點(diǎn)才能獲取相關(guān)資源。
  • 不同:在GraphQL中,Query類型的字段和任何其他類型的字段之間沒(méi)有區(qū)別,只是查詢的根目錄只能訪問(wèn)查詢類型。 例如,您可以在查詢的任何字段中擁有參數(shù)。 在REST中,沒(méi)有嵌套URL之類的概念。
  • 不同: 在REST中,通過(guò)將HTTP動(dòng)詞從GET更改為POST等其他內(nèi)容來(lái)指定寫入。 在GraphQL中,您可以更改查詢中的關(guān)鍵字。

由于上述相似性列表中的第一點(diǎn),人們經(jīng)常開始將Query類型的字段稱為GraphQL“端點(diǎn)”或“查詢”。 盡管這是一個(gè)合理的比較,但它可能會(huì)導(dǎo)致誤導(dǎo)性的觀點(diǎn),即查詢類型與其他類型顯著不同,而事實(shí)并非如此。

路由處理程序與解析程序

那么當(dāng)你實(shí)際調(diào)用API時(shí)會(huì)發(fā)生什么? 那么,通常它會(huì)在接收請(qǐng)求的服務(wù)器上執(zhí)行一些代碼。 該代碼可以執(zhí)行計(jì)算,從數(shù)據(jù)庫(kù)加載數(shù)據(jù),調(diào)用不同的API,或者真的做任何事情。 整個(gè)想法是你不需要從外面知道它在做什么。 但是REST和GraphQL都有相當(dāng)標(biāo)準(zhǔn)的方法來(lái)實(shí)現(xiàn)該API的內(nèi)部,并且將它們進(jìn)行比較以了解這些技術(shù)是如何不同的。

在這個(gè)比較中,我將使用JavaScript代碼,因?yàn)檫@是我最熟悉的,但是當(dāng)然,您可以在幾乎任何編程語(yǔ)言中實(shí)現(xiàn)REST和GraphQL API。 我也會(huì)跳過(guò)設(shè)置服務(wù)器所需的任何樣板文件,因?yàn)檫@對(duì)概念并不重要。

讓我們來(lái)看一下hello world中的一個(gè)快速示例,一個(gè)用于Node的流行API庫(kù):

app.get('/hello', function (req, res) {
 res.send('Hello World!')
})

在這里你看到我們已經(jīng)創(chuàng)建了一個(gè)返回字符串'Hello World!'的/hello端點(diǎn)。 從這個(gè)例子中,我們可以看到REST API服務(wù)器中HTTP請(qǐng)求的生命周期:

  1. 服務(wù)器收到請(qǐng)求并檢索HTTP動(dòng)詞(本例中為GET)和URL路徑
  2. API庫(kù)將動(dòng)詞和路徑與由服務(wù)器代碼注冊(cè)的函數(shù)進(jìn)行匹配
  3. 該函數(shù)執(zhí)行一次,并返回一個(gè)結(jié)果
  4. API庫(kù)序列化結(jié)果,添加適當(dāng)?shù)捻憫?yīng)代碼和標(biāo)題,并將其發(fā)送回客戶端

GraphQL的工作方式非常類似,也是相同的hello world example

const resolvers = { Query: {  hello: () => {   return 'Hello world!';
}, },};

正如你所看到的,我們不是為某個(gè)特定的URL提供一個(gè)函數(shù),而是提供了一個(gè)匹配某個(gè)類型的特定字段的函數(shù),在這種情況下,這個(gè)函數(shù)是Query類型的hello字段。 在GraphQL中,實(shí)現(xiàn)字段的這個(gè)函數(shù)被稱為 解析器。

為了發(fā)出請(qǐng)求,我們需要一個(gè)查詢:

query { hello}

因此,當(dāng)我們的服務(wù)器收到一個(gè)GraphQL請(qǐng)求時(shí)會(huì)發(fā)生什么情況:

  1. 服務(wù)器接收請(qǐng)求并檢索GraphQL查詢
  2. 遍歷查詢,并為每個(gè)字段調(diào)用適當(dāng)?shù)慕馕銎鳌?在這種情況下,只有一個(gè)字段,你好,它在查詢類型
  3. 函數(shù)被調(diào)用,并返回一個(gè)結(jié)果
  4. GraphQL庫(kù)和服務(wù)器將結(jié)果附加到與查詢形狀相匹配的響應(yīng)

所以你會(huì)接收到:

{ "hello": "Hello, world!" }

但是這里有一個(gè)技巧,我們實(shí)際上可以調(diào)用兩次這個(gè)Query!

query { hello secondHello: hello}

在這種情況下,同樣的生命周期發(fā)生在上面,但由于我們使用別名請(qǐng)求了兩次相同的字段,所以hello解析器實(shí)際上稱為twice。 這顯然是一個(gè)人為的例子,但重點(diǎn)是可以在一個(gè)請(qǐng)求中執(zhí)行多個(gè)字段,并且可以在查詢中的不同點(diǎn)處多次調(diào)用同一個(gè)字段。

沒(méi)有“嵌套”解析器的例子,這將是不完整的:

{ Query: {  author: (root, { id }) => find(authors, { id: id }), }, Author: {  posts: (author) => filter(posts, { authorId: author.id }), },}

這些解析器將能夠完成如下查詢:

query { author(id: 1) {  firstName  posts {   title  } }}

所以即使解析器的集合實(shí)際上是平坦的,因?yàn)樗鼈儽桓郊拥礁鞣N類型,您可以將它們構(gòu)建為嵌套查詢。在帖子中閱讀更多關(guān)于GraphQL執(zhí)行如何工作的信息 “GraphQL 解釋”.

結(jié)論

在這一天結(jié)束時(shí),REST和GraphQL API都是通過(guò)網(wǎng)絡(luò)調(diào)用功能的奇特方式。 如果您熟悉構(gòu)建REST API,那么實(shí)施GraphQL API不會(huì)有太大的不同。 但是GraphQL有很大的優(yōu)勢(shì),因?yàn)樗梢宰屇阏{(diào)用幾個(gè)相關(guān)的函數(shù)而不需要多次往返。

  • 相同: REST中的端點(diǎn)和GraphQL中的字段最終都會(huì)調(diào)用服務(wù)器上的函數(shù)。
  • 相同: REST和GraphQL通常都依賴于框架和庫(kù)來(lái)處理基本的聯(lián)網(wǎng)樣板。
  • 不同: 在REST中,每個(gè)請(qǐng)求通常只調(diào)用一個(gè)路由處理函數(shù)。 在GraphQL中,一個(gè)查詢可以調(diào)用許多解析器來(lái)構(gòu)造具有多個(gè)資源的嵌套響應(yīng)。
  • 不同: 在REST中,您自己構(gòu)建響應(yīng)的形狀。 在GraphQL中,響應(yīng)的形狀由GraphQL執(zhí)行庫(kù)構(gòu)建,以匹配查詢的形狀。

從本質(zhì)上講,您可以將GraphQL想象成一個(gè)在一個(gè)請(qǐng)求中調(diào)用多個(gè)嵌套端點(diǎn)的系統(tǒng)。 幾乎就像一個(gè)多路復(fù)用的REST。

所有的這些都意味著什么呢?

在這篇特別的文章中,我們沒(méi)有太多空間可以參與。 例如,對(duì)象標(biāo)識(shí),超媒體或高速緩存。 也許這將是以后的一個(gè)話題。 但是我希望你們同意,當(dāng)你看一看基本的知識(shí)時(shí),REST和GraphQL正在使用基本相似的概念。

我認(rèn)為GraphQL有一些差異。 特別是,我認(rèn)為能夠?qū)⒛腁PI作為一組小的解析器函數(shù)實(shí)現(xiàn)是非??岬?,然后有能力發(fā)送一個(gè)復(fù)雜的查詢,以可預(yù)測(cè)的方式一次檢索多個(gè)資源。 這節(jié)省了API實(shí)現(xiàn)者不必創(chuàng)建具有特定形狀的多個(gè)端點(diǎn),并且使得API消費(fèi)者能夠避免獲取他們不需要的額外數(shù)據(jù)。

另一方面,GraphQL沒(méi)有REST那么多的工具和集成。 例如,您無(wú)法像使用REST結(jié)果一樣輕松地緩存使用HTTP緩存的GraphQL結(jié)果。 但社區(qū)正在努力改善工具和基礎(chǔ)設(shè)施。 例如,您可以使用Apollo ClientRelay在您的前端緩存GraphQL結(jié)果,最近也可以在服務(wù)器上使用Apollo Engine.緩存GraphQL結(jié)果。

文章標(biāo)題:Rest相比GraphQL有什么好處?
轉(zhuǎn)載注明:http://www.muchs.cn/news33/105133.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營(yíng)銷型網(wǎng)站建設(shè)、服務(wù)器托管、小程序開發(fā)、靜態(tài)網(wǎng)站、關(guān)鍵詞優(yōu)化、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司