我為什麼要放棄RESTful,選擇擁抱GraphQL

来源:https://www.cnblogs.com/dotnet-college/archive/2023/02/04/17091996.html
-Advertisement-
Play Games

背景 REST作為一種現代網路應用非常流行的軟體架構風格,自從Roy Fielding博士在2000年他的博士論文中提出來到現在已經有了20年的歷史。它的簡單易用性,可擴展性,伸縮性受到廣大Web開發者的喜愛。 REST 的 API 配合JSON格式的數據交換,使得前後端分離、數據交互變得非常容易, ...


背景

REST作為一種現代網路應用非常流行的軟體架構風格,自從Roy Fielding博士在2000年他的博士論文中提出來到現在已經有了20年的歷史。它的簡單易用性,可擴展性,伸縮性受到廣大Web開發者的喜愛。

 REST 的 API 配合JSON格式的數據交換,使得前後端分離、數據交互變得非常容易,而且也已經成為了目前Web領域最受歡迎的軟體架構設計模式。

 

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

  • 濫用REST介面,導致大量相似度很高(具有重覆性)的API越來越冗餘。

  • 對於前端而言:REST API粒度較粗,難以一次性符合前端的數據要求,前端需要分多次請求介面數據。增加了前端人員的工作量。

  • 對於後端而言:前端需要的數據往往在不同的地方具有相似性,但卻又不同,比如針對同樣的用戶信息,有的地方只需要用戶簡要信息(比如頭像、昵稱),有些地方需要詳細的信息,這就需要開發不同的介面來滿足這些需求。當這樣的相似但又不同的地方多的時候,就需要開發更多的介面來滿足前端的需要。增加了後端開發人員的工作量和重覆度。

 

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

「做加法:」

產品需求增加,頁面需要增加功能,數據也就相應的要增加顯示,那麼REST介面也需要做增加,這種無可厚非。

「做減法:」

產品需求減少,頁面需要減少功能,或者減少某些信息顯示,那麼數據就要做減法。

 

一種通常懶惰的做法是,前端不與後端溝通,僅在前端對數據選擇性顯示。

 

因為後端介面能夠滿足數據需要,僅僅是在做顯示的時候對數據進行了選擇性顯示,但介面的數據是存在冗餘的,這種情況一個是存在數據泄露風險,另外就是數據量過大時造成網路流量過大,頁面載入緩慢,用戶流量費白白消耗,用戶體驗就會下降。

 

另外一種做法就是告知後端,要麼開發新的介面,要麼,修改舊介面,刪掉冗餘欄位。

但一般來說,開發新介面往往是後端開發人員會選擇的方案,因為這個方案對現有系統的影響最低,不會有額外的風險。

 

修改舊介面刪除冗餘數據的方案往往開發人員不會選擇,這是為什麼呢?

 

這就涉及到了系統的穩定性問題了,舊介面往往不止是一個地方在用,很有可能很多頁面、設置不同客戶端、不同服務都調用了這個介面獲取數據,不做詳細的調查,是不可能知道到底舊介面被調用了多少次,一旦改動舊介面,涉及範圍可能非常大,往往會引起其他地方出現崩潰。改動舊介面成本太高,所以往往不會被採取。

 

「同時做加減法:」

 

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

往往這個時候,其實用到的數據大多都是來自於同一個DO或者DTO,不過是在REST介面組裝數據時,用不同的VO來封裝不同欄位,或者,使用同樣的VO,組裝數據時做刪減。

 

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

 

所以需求頻繁改動是萬惡之源,當產品小哥哥改動需求時,程式員小哥哥可能正提著鐵鍬趕來......

 

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

 

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

 


Part 1 What is GraphQL

GraphQL簡介

  • GraphQL是一種新的API標準,它提供了一種比REST更有效、更強大和更靈活的替代方案。

  • 它是由Facebook開發並開源的,現在由來自世界各地的公司和個人組成的大型社區維護。

  • GraphQL本質上是一種基於api的查詢語言,現在大多數應用程式都需要從伺服器中獲取數據,這些數據存儲可能存儲在資料庫中,API的職責是提供與應用程式需求相匹配的存儲數據的介面。

  • 它是資料庫無關的,而且可以在使用API的任何環境中有效使用,我們可以理解為GraphQL是基於API之上的一層封裝,目的是為了更好,更靈活的適用於業務的需求變化。

簡單的來說,它

 

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

 

GraphQL 對比 REST API 有什麼好處?

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

 

客戶端拓展功能時要不斷編寫新介面(依賴於服務端),GraphQL 中一個服務僅暴露一個 GraphQL 層,消除了伺服器對數據格式的硬性規定,客戶端按需請求數據,可進行單獨維護和改進。

 

REST API 基於HTTP協議,不能靈活選擇網路協議,而傳輸層無關、資料庫技術無關使得 GraphQL 有更加靈活的技術棧選擇,能夠實現在網路協議層面優化應用。

 

舉個經典的例子:前端向後端請求一個book對象的數據及其作者信息。

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

先看REST API的做法:

 

再來看GraphQL是怎麼做的:

 

可以看出其中的區別:

  • 與REST多個endpoint不同,每一個的 GraphQL 服務其實對外只提供了一個用於調用內部介面的端點,所有的請求都訪問這個暴露出來的唯一端點。

Endpoints對比

 

REST API's Endpoints

 

  • GraphQL 實際上將多個 HTTP 請求聚合成了一個請求,將多個 restful 請求的資源變成了一個從根資源 POST 訪問其他資源的 Comment 和 Author 的圖,多個請求變成了一個請求的不同欄位,從原有的分散式請求變成了集中式的請求,因此GraphQL又可以被看成是圖資料庫的形式。

那我們已經能看到GraphQL的先進性,接下來看看它是怎麼做的。

 

GraphQL 思考模式

使用GraphQL介面設計獲取數據需要三步:

 

GraphQL獲取數據三步驟

 

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

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

  3. 後端GraphQL通過前端傳過來的請求,根據需要,自動組裝數據欄位,返回給前端。

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

總結它的好處:

在它的設計思想中,GraphQL 以圖的形式將整個 Web 服務中的資源展示出來,客戶端可以按照其需求自行調用,類似添加欄位的需求其實就不再需要後端多次修改了。

創建GraphQL伺服器的最終目標是:

允許查詢通過圖和節點的形式去獲取數據。


是什麼讓我放棄了restful api?瞭解清楚後我全面擁抱GraphQL

GraphQL執行邏輯

有人會問:

 

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

  • GraphQL需要直接對接資料庫嗎?

  • 使用GraphQL需要對現有的後端服務進行大刀闊斧的修改嗎?

 

答案是:NO!不需要!

 

它完全可以以一種不侵入的方式來部署,將它作為前後端的中間服務,也就是,現在開始逐漸流行的 前端 —— 中端 —— 後端 的三層結構模式來部署!

 

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

 

GraphQL執行邏輯

也就是說,完全可以搭建一個GraphQL伺服器,專門來處理前端請求,並處理後端服務獲取的數據,重新進行組裝、篩選、過濾,將完美符合前端需要的數據返回。

新的開發需求可以直接就使用GraphQL服務來獲取數據了,以前已經上線的功能無需改動,還是使用原有請求調用REST介面的方式,最低程度的降低更換GraphQL帶來的技術成本問題!

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

只有當原有需求發生變化,需要對原功能進行修改時,就可以換成GraphQL了。

GraphQL應用的基本架構

下圖是一個 GraphQL 應用的基本架構,其中客戶端只和 GraphQL 層進行 API 交互,而 GraphQL 層再往後接入各種數據源。這樣一來,只要是數據源有的數據, GraphQL 層都可以讓客戶端按需獲取,不必專門再去定介面了。

 

GraphQL應用基本架構

 

一個GraphQL服務僅暴露一個 GraphQL Endpoint,可以按照業務來進行區分,部署多個GraphQL服務,分管不同的業務數據,這樣就可以避免單伺服器壓力過大的問題了。

GraphQL特點總結

  • 聲明式數據獲取(可以對API進行查詢): 聲明式的數據查詢帶來了介面的精確返回,伺服器會按數據查詢的格式返回同樣結構的 JSON 數據、真正照顧了客戶端的靈活性。

  • 一個微服務僅暴露一個 GraphQL 層:一個微服務只需暴露一個GraphQL endpoint,客戶端請求相應數據只通過該端點按需獲取,不需要再額外定義其他介面。

  • 傳輸層無關、資料庫技術無關:帶來了更靈活的技術棧選擇,比如我們可以選擇對移動設備友好的協議,將網路傳輸數據量最小化,實現在網路協議層面優化應用。


GraphQL支持的數據操作

GraphQL對數據支持的操作有:

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

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

  • 訂閱(Subscription):用於監聽數據變動、並靠websocket等協議推送變動的消息給對方。

圖片

GraphQL支持的操作

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

要想要設計GraphQL的數據模型,用來描述你的業務數據,那麼就必須要有一套Schema語法來做支撐。

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

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

什麼是類型?

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

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

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

標量類型(Scalar Type)

標量是GraphQL類型系統中最小的顆粒。類似於Java、C#中的基本類型。

其中內建標量主要有:

  • String

  • Int

  • Float

  • Boolean

  • Enum

  • ID

上面的類型僅僅是GraphQL預設內置的類型,當然,為了保證最大的靈活性,GraphQL還可以很靈活的自行創建標量類型。

對象類型(Object Type)

僅有標量類型是不能滿足複雜抽象數據模型的需要,這時候我們可以使用對象類型。

通過對象模型來構建GraphQL中關於一個數據模型的形狀,同時還可以聲明各個模型之間的內在關聯(一對多、一對一或多對多)。

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

 

對象模型引入關聯關係

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

類型修飾符(Type Modifier)

那麼,類型系統僅僅只有類型定義是不夠的,我們還需要對類型進行更廣泛性的描述。

類型修飾符就是用來修飾類型,以達到額外的數據類型要求控制。

比如:

  • 列表:[Type]

  • 非空:Type!

  • 列表非空:[Type]!

  • 非空列表,列表內容類型非空:[Type!]!

在描述數據模型(模式Schema)時,就可以對欄位施加限制條件。

例如定義了一個名為User的對象類型,並對其欄位進行定義和施加限制條件:

User欄位控制

那麼,返回數據時,像下麵這種情況就是不允許的:

 

Graphql會根據Schema Type來自動返回正確的數據:

 

其他類型

除了上面的,Graphql還有一些其他類型來更好的引入面向對象的設計思想:

  • 介面類型(Interfaces):其他對象類型實現介面必須包含介面所有的欄位,並具有相同的類型修飾符,才算實現介面。

比如定義了一個介面類型:

 

那麼就可以實現該介面:

  •  

    聯合類型(Union Types):聯合類型和介面十分相似,但是它並不指定類型之間的任何共同欄位。幾個對象類型共用一個聯合類型。

 

  • 輸入類型(Input Types):更新數據時有用,與常規對象只有關鍵字修飾不一樣,常規對象時 type 修飾,輸入類型是 input 修飾。

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

 

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

 

所以,這樣面向對象的設計方式,真的對後端開發人員特別友好!而且前端MVVM框架流行以來,面向對象的設計思想也越來越流行,前端使用Graphql也會得心應手。

 


Graphql 技術接入架構

那麼,該怎麼設計來接入我們現有的系統中呢?

  • 將Graphql服務直連資料庫的方式:最簡潔的配置,直接操作資料庫能減少中間環節的性能消耗。

直連資料庫的接入

  • 集成現有服務的GraphQL層:這種配置適合於舊服務的改造,尤其是在涉及第三方服務時、依然可以通過原有介面進行交互。

 

集成現有服務的GraphQL層
  • 直連資料庫和集成服務的混合模式:前兩種方式的混合。

 

混合接入方式

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


 

服務端實現

在服務端, GraphQL 伺服器可用任何可構建 Web 伺服器的語言實現。有以下語言的實現供參考:

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

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

客戶端實現

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

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

覆蓋了眾多客戶端設計語言,而其他語言的支持也在推進中。

Graphql的一些服務

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

  • Apollo Engine:一個用於監視 GraphQL 後端的性能和使用的服務。

  • Graphcool (github): 一個 BaaS(後端即服務),它為你的應用程式提供了一個 GraphQL 後端,且具有用於管理資料庫和存儲數據的強大的 web ui。

  • Tipe (github): 一個 SaaS(軟體即服務)內容管理系統,允許你使用強大的編輯工具創建你 的內容,並通過 GraphQL 或 REST API 從任何地方訪問它。

  • AWS AppSync:完全托管的 GraphQL 服務,包含實時訂閱、離線編程和同步、企業級安全特性以及細粒度的授權控制。

  • Hasura:一個 BaaS(後端即服務),允許你在 Postgres 上創建數據表、定義許可權並使用 GraphQL 介面查詢和操作。

Graphql的一些工具

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

  • Graphql Language Service: 一個用於構建 IDE 的 GraphQL 語言服務(診斷、自動完成等) 的介面。

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

想要獲取更多關於Graphql的一些框架、工具,可以去awesome-graphql:一個神奇的社區,維護一系列庫、資源等,地址是

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

想要學習更多Graphql的知識,可以去GraphQL.cn。


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

  • 不知道你懂得它的原理和優點了嗎?

  • 你對它感興趣嗎?

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

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

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.編寫一個計算減法的方法,當第一個數小於第二個數時,拋出“被減數不能小於減數"的異常。 class Sub(Exception): def __init__(self, x, y): self.x = x self.y = y try: a = int(input('請輸入被減數')) b = i ...
  • 文中代碼 smart_girl = {"name":"yuan wai", "age": 25,"address":"Beijing"} 第一種方式:pop()方法 註意:找不到對應的key,pop方法會拋出異常KeyError smart_girl.pop("name") #返回值是value # ...
  • 1.已知列表li_num1 = [4, 5, 2, 7]和li_num2 = [3, 6],請將這兩個列表合併為一個列表,並將合併後的列表中的元素按降序排列。 1 # 方法一 2 li_num1 = [4, 5, 2, 7, ] 3 li_num2 = [3, 6] 4 # extend() 函數用 ...
  • 1、netty如何解析多協議 前提: 項目地址:https://gitee.com/q529075990qqcom/NB-IOT.git 我們需要一個創建mavne項目,這個項目是我已經寫好的項目,項目結構圖如下: 創建公共模塊 創建子模塊,準備好依賴Netty4.1版本 <dependencies ...
  • 在磁碟上讀寫文件的功能都是由操作系統提供的,現代操作系統不允許普通的程式直接操作磁碟,所以,讀寫文件就是請求操作系統打開一個文件對象(通常稱為文件描述符),然後,通過操作系統提供的介面從這個文件對象中讀取數據(讀文件),或者把數據寫入這個文件對象(寫文件)。 1.讀文件 要以讀文件的模式打開一個文件 ...
  • 註釋 單行註釋:對某一行進行註釋,使用“/註釋內容/”標識 多行註釋:可以書寫多行,使用“/*註釋內容*//”表示 文檔註釋:這個內容對IDEA是有意義的,/**註釋內容*/ public class Hello { //單行註釋 //註釋後會被編譯器忽略,不會作為語句編譯 //每個單行註釋只能寫一 ...
  • 哈嘍兄弟們,今天咱們來學習一下Python字典修改元素的四種方式。 本文中使用的字典對象: smart_girl = {"name":"yuan wai", "age": 25} 第一種方式:[key] smart_girl["age"] = 35 說明:字典中存在key時為修改value、不存在k ...
  • 一、最終效果 遠程開機app下載: 下載鏈接:https://wwp.lanzoup.com/iDR330ml4l2b 提取碼 : dxcg 註意:使用前請按照2.1的步驟設置電腦“ mac地址:填寫自己的mac地址 主機地址:填寫自己的公網ip,百度搜索ip 映射埠:第二點準備工作裡面配置的映射 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...