<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          是什么讓我放棄了restful api?了解清楚后我全面擁抱GraphQL

          共 7019字,需瀏覽 15分鐘

           ·

          2021-01-15 08:10

          來源:toutiao.com/a6833818331884028419


          背景

          REST作為一種現(xiàn)代網(wǎng)絡(luò)應(yīng)用非常流行的軟件架構(gòu)風(fēng)格,自從Roy Fielding博士在2000年他的博士論文中提出來到現(xiàn)在已經(jīng)有了20年的歷史。它的簡單易用性,可擴(kuò)展性,伸縮性受到廣大Web開發(fā)者的喜愛。

          REST 的 API 配合JSON格式的數(shù)據(jù)交換,使得前后端分離、數(shù)據(jù)交互變得非常容易,而且也已經(jīng)成為了目前Web領(lǐng)域最受歡迎的軟件架構(gòu)設(shè)計模式。

          但隨著REST API的流行和發(fā)展,它的缺點也暴露了出來:

          • 濫用REST接口,導(dǎo)致大量相似度很高(具有重復(fù)性)的API越來越冗余。

          • 對于前端而言:REST API粒度較粗,難以一次性符合前端的數(shù)據(jù)要求,前端需要分多次請求接口數(shù)據(jù)。增加了前端人員的工作量。

          • 對于后端而言:前端需要的數(shù)據(jù)往往在不同的地方具有相似性,但卻又不同,比如針對同樣的用戶信息,有的地方只需要用戶簡要信息(比如頭像、昵稱),有些地方需要詳細(xì)的信息,這就需要開發(fā)不同的接口來滿足這些需求。當(dāng)這樣的相似但又不同的地方多的時候,就需要開發(fā)更多的接口來滿足前端的需要。增加了后端開發(fā)人員的工作量和重復(fù)度。

          那我們來分析一下,當(dāng)前端需求變化,涉及到改動舊需求時,會有以下這些情況:

          「做加法:」

          產(chǎn)品需求增加,頁面需要增加功能,數(shù)據(jù)也就相應(yīng)的要增加顯示,那么REST接口也需要做增加,這種無可厚非。

          「做減法:」

          產(chǎn)品需求減少,頁面需要減少功能,或者減少某些信息顯示,那么數(shù)據(jù)就要做減法。

          一種通常懶惰的做法是,前端不與后端溝通,僅在前端對數(shù)據(jù)選擇性顯示。

          因為后端接口能夠滿足數(shù)據(jù)需要,僅僅是在做顯示的時候?qū)?shù)據(jù)進(jìn)行了選擇性顯示,但接口的數(shù)據(jù)是存在冗余的,這種情況一個是存在數(shù)據(jù)泄露風(fēng)險,另外就是數(shù)據(jù)量過大時造成網(wǎng)絡(luò)流量過大,頁面加載緩慢,用戶流量費白白消耗,用戶體驗就會下降。

          另外一種做法就是告知后端,要么開發(fā)新的接口,要么,修改舊接口,刪掉冗余字段。

          但一般來說,開發(fā)新接口往往是后端開發(fā)人員會選擇的方案,因為這個方案對現(xiàn)有系統(tǒng)的影響最低,不會有額外的風(fēng)險。

          修改舊接口刪除冗余數(shù)據(jù)的方案往往開發(fā)人員不會選擇,這是為什么呢?

          這就涉及到了系統(tǒng)的穩(wěn)定性問題了,舊接口往往不止是一個地方在用,很有可能很多頁面、設(shè)置不同客戶端、不同服務(wù)都調(diào)用了這個接口獲取數(shù)據(jù),不做詳細(xì)的調(diào)查,是不可能知道到底舊接口被調(diào)用了多少次,一旦改動舊接口,涉及范圍可能非常大,往往會引起其他地方出現(xiàn)崩潰。改動舊接口成本太高,所以往往不會被采取。

          「同時做加減法:」

          既有加法,又有減法,其實這種就跟新需求沒啥區(qū)別,前端需要重做頁面,后端需要新寫接口滿足前端需要,但是舊接口還是不能輕舉妄動(除非確定只有這一處調(diào)用才可以刪除)。

          往往這個時候,其實用到的數(shù)據(jù)大多都是來自于同一個DO或者DTO,不過是在REST接口組裝數(shù)據(jù)時,用不同的VO來封裝不同字段,或者,使用同樣的VO,組裝數(shù)據(jù)時做刪減。

          看到這些問題是不是覺得令人頭大?

          所以需求頻繁改動是萬惡之源,當(dāng)產(chǎn)品小哥哥改動需求時,程序員小哥哥可能正提著鐵鍬趕來......

          那么有沒有一種方案或者框架,可以使得在用到同一個領(lǐng)域模型(DO或者DTO)的數(shù)據(jù)時,前端對于這個模型的數(shù)據(jù)字段需求的改動,后端可以根據(jù)前端的改動和需要,自動適配,自動組裝需要的字段,返回給前端呢?如果能這樣做的話,那么后端程序猿小哥可能要開心死了,前端妹子也不用那么苦口婆心地勸說后端小哥哥了。

          所以GraphQL隆重出世了!那么問題來了!


          Part 1 What is GraphQL

          GraphQL簡介

          • GraphQL是一種新的API標(biāo)準(zhǔn),它提供了一種比REST更有效、更強大和更靈活的替代方案。

          • 它是由Facebook開發(fā)并開源的,現(xiàn)在由來自世界各地的公司和個人組成的大型社區(qū)維護(hù)。

          • GraphQL本質(zhì)上是一種基于api的查詢語言,現(xiàn)在大多數(shù)應(yīng)用程序都需要從服務(wù)器中獲取數(shù)據(jù),這些數(shù)據(jù)存儲可能存儲在數(shù)據(jù)庫中,API的職責(zé)是提供與應(yīng)用程序需求相匹配的存儲數(shù)據(jù)的接口。

          • 它是數(shù)據(jù)庫無關(guān)的,而且可以在使用API的任何環(huán)境中有效使用,我們可以理解為GraphQL是基于API之上的一層封裝,目的是為了更好,更靈活的適用于業(yè)務(wù)的需求變化。

          簡單的來說,它

          它的工作模式是這樣子的:

          GraphQL 對比 REST API 有什么好處?

          REST API 的接口靈活性差、接口操作流程繁瑣,GraphQL 的聲明式數(shù)據(jù)獲取,使得接口數(shù)據(jù)精確返回,數(shù)據(jù)查詢流程簡潔,照顧了客戶端的靈活性。

          客戶端拓展功能時要不斷編寫新接口(依賴于服務(wù)端),GraphQL 中一個服務(wù)僅暴露一個 GraphQL 層,消除了服務(wù)器對數(shù)據(jù)格式的硬性規(guī)定,客戶端按需請求數(shù)據(jù),可進(jìn)行單獨維護(hù)和改進(jìn)。

          REST API 基于HTTP協(xié)議,不能靈活選擇網(wǎng)絡(luò)協(xié)議,而傳輸層無關(guān)、數(shù)據(jù)庫技術(shù)無關(guān)使得 GraphQL 有更加靈活的技術(shù)棧選擇,能夠?qū)崿F(xiàn)在網(wǎng)絡(luò)協(xié)議層面優(yōu)化應(yīng)用。

          舉個經(jīng)典的例子:前端向后端請求一個book對象的數(shù)據(jù)及其作者信息。

          我用動圖來分別演示下REST和GraphQL是怎么樣的一個過程。

          先看REST API的做法:

          REST API獲取數(shù)據(jù)

          再來看GraphQL是怎么做的:

          GraphQL獲取數(shù)據(jù)

          可以看出其中的區(qū)別:

          • 與REST多個endpoint不同,每一個的 GraphQL 服務(wù)其實對外只提供了一個用于調(diào)用內(nèi)部接口的端點,所有的請求都訪問這個暴露出來的唯一端點。
          Endpoints對比
          REST API's Endpoints
          • GraphQL 實際上將多個 HTTP 請求聚合成了一個請求,將多個 restful 請求的資源變成了一個從根資源 POST 訪問其他資源的 Comment 和 Author 的圖,多個請求變成了一個請求的不同字段,從原有的分散式請求變成了集中式的請求,因此GraphQL又可以被看成是圖數(shù)據(jù)庫的形式。
          圖數(shù)據(jù)庫模式的數(shù)據(jù)查詢

          那我們已經(jīng)能看到GraphQL的先進(jìn)性,接下來看看它是怎么做的。

          GraphQL 思考模式

          使用GraphQL接口設(shè)計獲取數(shù)據(jù)需要三步:

          GraphQL獲取數(shù)據(jù)三步驟

          1. 首先要設(shè)計數(shù)據(jù)模型,用來描述數(shù)據(jù)對象,它的作用可以看做是VO,用于告知GraphQL如何來描述定義的數(shù)據(jù),為下一步查詢返回做準(zhǔn)備;

          2. 前端使用模式查詢語言(Schema)來描述需要請求的數(shù)據(jù)對象類型和具體需要的字段(稱之為聲明式數(shù)據(jù)獲取);

          3. 后端GraphQL通過前端傳過來的請求,根據(jù)需要,自動組裝數(shù)據(jù)字段,返回給前端。

          GraphQL的這種思考模式是不是完美解決了之前遇到的問題呢?!

          總結(jié)它的好處:

          在它的設(shè)計思想中,GraphQL 以圖的形式將整個 Web 服務(wù)中的資源展示出來,客戶端可以按照其需求自行調(diào)用,類似添加字段的需求其實就不再需要后端多次修改了。

          創(chuàng)建GraphQL服務(wù)器的最終目標(biāo)是:

          允許查詢通過圖和節(jié)點的形式去獲取數(shù)據(jù)。

          Project Overview

          GraphQL執(zhí)行邏輯

          有人會問:

          • 使用了GraphQL就要完全拋棄REST了嗎?

          • GraphQL需要直接對接數(shù)據(jù)庫嗎?

          • 使用GraphQL需要對現(xiàn)有的后端服務(wù)進(jìn)行大刀闊斧的修改嗎?

          答案是:NO!不需要!

          它完全可以以一種不侵入的方式來部署,將它作為前后端的中間服務(wù),也就是,現(xiàn)在開始逐漸流行的?前端 —— 中端 —— 后端?的三層結(jié)構(gòu)模式來部署!

          那就來看一下這樣的部署模式圖:

          GraphQL執(zhí)行邏輯

          也就是說,完全可以搭建一個GraphQL服務(wù)器,專門來處理前端請求,并處理后端服務(wù)獲取的數(shù)據(jù),重新進(jìn)行組裝、篩選、過濾,將完美符合前端需要的數(shù)據(jù)返回。

          新的開發(fā)需求可以直接就使用GraphQL服務(wù)來獲取數(shù)據(jù)了,以前已經(jīng)上線的功能無需改動,還是使用原有請求調(diào)用REST接口的方式,最低程度的降低更換GraphQL帶來的技術(shù)成本問題!

          如果沒有那么多成本來支撐改造,那么就不需要改造!

          只有當(dāng)原有需求發(fā)生變化,需要對原功能進(jìn)行修改時,就可以換成GraphQL了。

          GraphQL應(yīng)用的基本架構(gòu)

          下圖是一個 GraphQL 應(yīng)用的基本架構(gòu),其中客戶端只和 GraphQL 層進(jìn)行 API 交互,而 GraphQL 層再往后接入各種數(shù)據(jù)源。這樣一來,只要是數(shù)據(jù)源有的數(shù)據(jù), GraphQL 層都可以讓客戶端按需獲取,不必專門再去定接口了。

          GraphQL應(yīng)用基本架構(gòu)

          一個GraphQL服務(wù)僅暴露一個 GraphQL Endpoint,可以按照業(yè)務(wù)來進(jìn)行區(qū)分,部署多個GraphQL服務(wù),分管不同的業(yè)務(wù)數(shù)據(jù),這樣就可以避免單服務(wù)器壓力過大的問題了。

          GraphQL特點總結(jié)

          • 聲明式數(shù)據(jù)獲取(可以對API進(jìn)行查詢):?聲明式的數(shù)據(jù)查詢帶來了接口的精確返回,服務(wù)器會按數(shù)據(jù)查詢的格式返回同樣結(jié)構(gòu)的 JSON 數(shù)據(jù)、真正照顧了客戶端的靈活性。

          • 一個微服務(wù)僅暴露一個 GraphQL 層:一個微服務(wù)只需暴露一個GraphQL endpoint,客戶端請求相應(yīng)數(shù)據(jù)只通過該端點按需獲取,不需要再額外定義其他接口。

          • 傳輸層無關(guān)、數(shù)據(jù)庫技術(shù)無關(guān):帶來了更靈活的技術(shù)棧選擇,比如我們可以選擇對移動設(shè)備友好的協(xié)議,將網(wǎng)絡(luò)傳輸數(shù)據(jù)量最小化,實現(xiàn)在網(wǎng)絡(luò)協(xié)議層面優(yōu)化應(yīng)用。


          Part 2 Schema & Type

          GraphQL支持的數(shù)據(jù)操作

          GraphQL對數(shù)據(jù)支持的操作有:

          • 查詢(Query):獲取數(shù)據(jù)的基本查詢。

          • 變更(Mutation):支持對數(shù)據(jù)的增刪改等操作。

          • 訂閱(Subscription):用于監(jiān)聽數(shù)據(jù)變動、并靠websocket等協(xié)議推送變動的消息給對方。

          GraphQL支持的操作

          GraphQL的核心概念:圖表模式(Schema)

          要想要設(shè)計GraphQL的數(shù)據(jù)模型,用來描述你的業(yè)務(wù)數(shù)據(jù),那么就必須要有一套Schema語法來做支撐。

          想要描述數(shù)據(jù),就必須離不開數(shù)據(jù)類型的定義。所以GraphQL設(shè)計了一套Schema模式(可以理解為語法),其中最重要的就是數(shù)據(jù)類型的定義和支持。

          那么類型(Type)就是模式(Schema)最核心的東西了。

          什么是類型?

          • 對于數(shù)據(jù)模型的抽象是通過類型(Type)來描述的,每一個類型有若干字段(Field)組成,每個字段又分別指向某個類型(Type)。這很像Java、C#中的類(Class)。

          • GraphQL的Type簡單可以分為兩種,一種叫做Scalar Type(標(biāo)量類型),另一種叫做Object Type(對象類型)。

          那么就分別來介紹下兩種類型。

          標(biāo)量類型(Scalar Type)

          標(biāo)量是GraphQL類型系統(tǒng)中最小的顆粒。類似于Java、C#中的基本類型。

          其中內(nèi)建標(biāo)量主要有:

          • String

          • Int

          • Float

          • Boolean

          • Enum

          • ID

          Scalar Type

          上面的類型僅僅是GraphQL默認(rèn)內(nèi)置的類型,當(dāng)然,為了保證最大的靈活性,GraphQL還可以很靈活的自行創(chuàng)建標(biāo)量類型。

          對象類型(Object Type)

          僅有標(biāo)量類型是不能滿足復(fù)雜抽象數(shù)據(jù)模型的需要,這時候我們可以使用對象類型。

          通過對象模型來構(gòu)建GraphQL中關(guān)于一個數(shù)據(jù)模型的形狀,同時還可以聲明各個模型之間的內(nèi)在關(guān)聯(lián)(一對多、一對一或多對多)。

          對象類型的定義可以參考下圖:

          對象模型引入關(guān)聯(lián)關(guān)系

          是不是很方便呢?我們可以像設(shè)計類圖一樣來設(shè)計GraphQL的對象模型。

          類型修飾符(Type Modifier)

          那么,類型系統(tǒng)僅僅只有類型定義是不夠的,我們還需要對類型進(jìn)行更廣泛性的描述。

          類型修飾符就是用來修飾類型,以達(dá)到額外的數(shù)據(jù)類型要求控制。

          比如:

          • 列表:[Type]

          • 非空:Type!

          • 列表非空:[Type]!

          • 非空列表,列表內(nèi)容類型非空:[Type!]!

          在描述數(shù)據(jù)模型(模式Schema)時,就可以對字段施加限制條件。

          例如定義了一個名為User的對象類型,并對其字段進(jìn)行定義和施加限制條件:

          User字段控制

          那么,返回數(shù)據(jù)時,像下面這種情況就是不允許的:

          錯誤的表示

          Graphql會根據(jù)Schema Type來自動返回正確的數(shù)據(jù):

          正確的表示

          其他類型

          除了上面的,Graphql還有一些其他類型來更好的引入面向?qū)ο蟮脑O(shè)計思想:

          • 接口類型(Interfaces):其他對象類型實現(xiàn)接口必須包含接口所有的字段,并具有相同的類型修飾符,才算實現(xiàn)接口。

          比如定義了一個接口類型:

          那么就可以實現(xiàn)該接口:

          • 聯(lián)合類型(Union Types):聯(lián)合類型和接口十分相似,但是它并不指定類型之間的任何共同字段。幾個對象類型共用一個聯(lián)合類型。
          • 輸入類型(Input Types):更新數(shù)據(jù)時有用,與常規(guī)對象只有關(guān)鍵字修飾不一樣,常規(guī)對象時 type 修飾,輸入類型是 input 修飾。

          比如定義了一個輸入類型:

          前端發(fā)送變更請求時就可以使用(通過參數(shù)來指定輸入的類型):

          所以,這樣面向?qū)ο蟮脑O(shè)計方式,真的對后端開發(fā)人員特別友好!而且前端MVVM框架流行以來,面向?qū)ο蟮脑O(shè)計思想也越來越流行,前端使用Graphql也會得心應(yīng)手。


          Part 3 GraphQL技術(shù)接入架構(gòu)

          Graphql 技術(shù)接入架構(gòu)

          那么,該怎么設(shè)計來接入我們現(xiàn)有的系統(tǒng)中呢?

          • 將Graphql服務(wù)直連數(shù)據(jù)庫的方式:最簡潔的配置,直接操作數(shù)據(jù)庫能減少中間環(huán)節(jié)的性能消耗。
          直連數(shù)據(jù)庫的接入
          • 集成現(xiàn)有服務(wù)的GraphQL層:這種配置適合于舊服務(wù)的改造,尤其是在涉及第三方服務(wù)時、依然可以通過原有接口進(jìn)行交互。
          集成現(xiàn)有服務(wù)的GraphQL層
          • 直連數(shù)據(jù)庫和集成服務(wù)的混合模式:前兩種方式的混合。
          混合接入方式

          可以說是非常靈活了!你都不用擔(dān)心會給你帶來任何的麻煩。


          服務(wù)端實現(xiàn)

          在服務(wù)端, GraphQL 服務(wù)器可用任何可構(gòu)建 Web 服務(wù)器的語言實現(xiàn)。有以下語言的實現(xiàn)供參考:

          • C# / .NET
          • Clojure
          • Elixir
          • Erlang
          • Go
          • Groovy
          • Java
          • JavaScript
          • Julia
          • Kotlin
          • Perl
          • PHP
          • Python
          • R
          • Ruby
          • Rust
          • Scala
          • Swift

          種類繁多,幾乎流行的語言都有支持。

          客戶端實現(xiàn)

          在客戶端,Graphql Client目前有下面的語言支持:

          • C# / .NET
          • Clojurescript
          • Elm
          • Flutter
          • Go
          • Java / Android
          • JavaScript
          • Julia
          • Swift / Objective-C iOS
          • Python
          • R

          覆蓋了眾多客戶端設(shè)計語言,而其他語言的支持也在推進(jìn)中。

          Graphql的一些服務(wù)

          整理了下目前比較流行的服務(wù)框架:

          • Apollo Engine:一個用于監(jiān)視 GraphQL 后端的性能和使用的服務(wù)。

          • Graphcool (github): 一個 BaaS(后端即服務(wù)),它為你的應(yīng)用程序提供了一個 GraphQL 后端,且具有用于管理數(shù)據(jù)庫和存儲數(shù)據(jù)的強大的 web ui。

          • Tipe (github): 一個 SaaS(軟件即服務(wù))內(nèi)容管理系統(tǒng),允許你使用強大的編輯工具創(chuàng)建你 的內(nèi)容,并通過 GraphQL 或 REST API 從任何地方訪問它。

          • AWS AppSync:完全托管的 GraphQL 服務(wù),包含實時訂閱、離線編程和同步、企業(yè)級安全特性以及細(xì)粒度的授權(quán)控制。

          • Hasura:一個 BaaS(后端即服務(wù)),允許你在 Postgres 上創(chuàng)建數(shù)據(jù)表、定義權(quán)限并使用 GraphQL 接口查詢和操作。

          Graphql的一些工具

          • graphiql (npm): 一個交互式的運行于瀏覽器中的 GraphQL IDE。

          • Graphql Language Service: 一個用于構(gòu)建 IDE 的 GraphQL 語言服務(wù)(診斷、自動完成等) 的接口。

          • quicktype (github): 在 TypeScript、Swift、golang、C#、C++ 等語言中為 GraphQL 查 詢生成類型。

          想要獲取更多關(guān)于Graphql的一些框架、工具,可以去awesome-graphql:一個神奇的社區(qū),維護(hù)一系列庫、資源等,地址是

          https://github.com/chentsulin/awesome-graphql。

          想要學(xué)習(xí)更多Graphql的知識,可以去GraphQL.cn。


          好了,一個入門級的Graphql介紹篇就這樣完結(jié)了(盡管篇幅也很大哈哈)。

          • 不知道你懂得它的原理和優(yōu)點了嗎?

          • 你對它感興趣嗎?

          • 看完這篇介紹,有沒有想動手嘗試一下呢?

          • 你會在你下一個項目中引入Graphql并使用它嗎?

          • 你對Graphql還有什么疑惑的問題呢?

          PS:如果覺得我的分享不錯,歡迎大家隨手點贊、在看。
          END

          推薦閱讀

          分享基于 Spring Cloud +OAuth2 的權(quán)限管理系統(tǒng)

          鏈家程序員刪公司9TB 數(shù)據(jù) 被判7年

          工作10年后,再看String s = new String("xyz") 創(chuàng)建了幾個對象?

          SpringBoot集成WebSocket,實現(xiàn)后臺向前端推送信息

          SpringBoot 配置 ELK 環(huán)境

          給代碼寫注釋時有哪些講究?

          程序員該如何把 Windows 系統(tǒng)打造的跟 Mac 一樣牛逼?

          基于 SpringBoot,來實現(xiàn)MySQL讀寫分離技術(shù)

          瀏覽 23
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日比视频网站 | 高清国产视频在线观看 | 精品人妻一区二区三区奶水 | av在线手机 | 亚洲yw无码在线免费观看 |