Rest相比GraphQL有什么好處?

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

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

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

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

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

資源

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

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

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

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

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

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

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

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

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

現(xiàn)在,我們可以發(fā)送類似于上面的REST請求的請求,但是這次使用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)容,即使兩者都可以通過URL請求,并且兩者都可以返回相同形式的JSON響應(yīng)。

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

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

結(jié)論

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

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

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

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

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

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

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

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

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

在GraphQL中,如上所述,您不使用URL來標(biāo)識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路由相比,這里有一些有趣的地方。 首先,不是將一個不同的HTTP動詞發(fā)送到相同的URL來區(qū)分讀取和寫入,而是使用不同的 initial type --- Mutation vs. Query。 在GraphQL文檔中,您可以選擇使用關(guān)鍵字發(fā)送哪種類型的操作:

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

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

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

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

結(jié)論

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

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

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

路由處理程序與解析程序

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

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

讓我們來看一下hello world中的一個快速示例,一個用于Node的流行API庫:

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

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

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

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

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

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

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

query { hello}

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

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

所以你會接收到:

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

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

query { hello secondHello: hello}

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

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

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

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

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

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

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

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

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

網(wǎng)站名稱:Rest相比GraphQL有什么好處?
轉(zhuǎn)載來源:http://www.bm7419.com/news/105133.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站收錄、軟件開發(fā)、網(wǎng)站排名、用戶體驗(yàn)品牌網(wǎng)站制作

廣告

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

綿陽服務(wù)器托管