使用ASP.NET Core開發GraphQL伺服器 -- 預備知識(上)

solenovex發表於2018-10-03

為了介紹使用ASP.NET Core構建GraphQL伺服器,本文需要介紹一下GraphQL,其實看官網的文件就行。

 

什麼是GraphQL?

GraphQL 既是一種用於 API 的查詢語言也是一個滿足你資料查詢的執行時。 GraphQL 對你的 API 中的資料提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的資料,而且沒有任何冗餘,也讓 API 更容易地隨著時間推移而演進,還能用於構建強大的開發者工具。

 

官網地址:https://graphql.org/

中文網址(感覺不是官方的,連HTTPS都不是):http://graphql.cn/

GraphQL來自Facebook,它於2012年開始開發,2015年開源。

 

GraphQL與程式語言無關,可以使用很多種語言/框架來構建Graph 伺服器,包括.NET Core。

像Github,Pinterest,Coursera等公司都在使用GraphQL。

 

Github的API到目前有4個版本,第三個版本都是用的是REST,而第四個版本使用的是GraphQL。

 

GraphQL到底是什麼?

這就是一個GraphQL查詢的例子。左邊是查詢,右邊是結果。

從這個例子可以看出,查詢是可以巢狀的,所以使用GraphQL的客戶端可以通過一次請求獲得所有需要的資料

 

每當對GraphQL伺服器進行查詢的時候,這些查詢首先都會依據一個型別系統對其進行驗證。每個GraphQL服務都會在GraphQL schema裡定義型別資訊。

可以把這個型別系統看作是你的API資料的藍本,它由你定義的一系列物件所支撐。

例如這個User物件:

 

GraphQL經常被稱作是一個:宣告式資料獲取語言。

 

GraphQL的設計原則

  • 分層結構:GraphQL的查詢是有層次結構的,欄位可以內嵌其它欄位;查詢和返回資料的結構是一致的。
  • 以產品中心:GraphQL是由客戶端所需要的資料所驅動,語言和執行時也支援客戶端。
  • 強型別:GraphQL伺服器由GraphQL型別系統所支撐。在schema裡,每個資料點都有一個特定的型別,針對這個型別還有驗證。
  • 客戶端定製查詢:GraphQL伺服器提供了可以讓客戶端進行定製查詢的能力。
  • 內省(introspective):客戶端可以查詢GraphQL伺服器的型別系(schema)。

 

為什麼使用GraphQL?

談起GraphQL,總是離不開REST。

如果您想了解REST in ASP.NET Core,請看我寫的這個系列文章:https://www.cnblogs.com/cgzl/p/9178672.html#rest

REST有幾個問題:

過度獲取:REST裡GET請求的查詢結果通常比較大,並且超過了客戶端的需求:

這裡我只需要name,height,和mass,但是卻返回了所有的欄位。

 

而使用GraphQL,我只需要查詢我需要的資料:

 

獲取不足:使用REST時,我想獲取部門和部門的人員,通常我需要先請求查詢部門列表;然後遍歷返回的部門列表,再次發出請求查詢每個部門下的人員,所以是N+1查詢。

而使用GraphQL,我就可以通過一個查詢請求(巢狀的)取得相應的結果。

 

不靈活:隨著API的演進,REST需要隨時建立新的端點,所以REST API的端點增長速度很快;此外有版本和相容性需要謹慎考慮。

而GraphQL,典型的結構是隻有一個端點。這個單端點就像API閘道器一樣組織了多個資料來源,這樣就會更簡單。

 

綜上,使用GraphQL的好處是:

  • 避免多重REST請求
  • 向下相容,無需考慮版本
  • 可以對現有的資料來源(例如REST API)進行包裝
  • 與開發語言無關

 

GraphQL查詢

我通過Github的GraphQL Explorer來進行演示,網址是:https://developer.github.com/v4/explorer/

登入之後,其效果如下:

Github使用了graphiql,graphiql是一個瀏覽器內的IDE,它可以用來瀏覽和查詢GraphQL。

graphiql的網址是:https://github.com/graphql/graphiql

下一篇文章,我也會在.NET專案裡安裝這個graphiql。

graphiql只是用來瀏覽查詢GraphQL的一個瀏覽工具而已,其它比較流行的工具還包括GraphQL Playground 和 GraphQL Voyager等。

 

第一個查詢

開啟Github的GraphiQL以後,自動載入了一個查詢語句,我們點選執行按鈕,右側就會返回查詢的結果:

 

在這裡,我查詢了瀏覽者 viewer這個欄位,當前瀏覽該網頁的就是我自己;在查詢裡我還包括了viewer下的login欄位,也就是登入名。

結果以JSON形式返回,其資料包含在data屬性下,結構和查詢結構一致。

 

如果我還想在查詢中包含瀏覽者的姓名,那就加一個欄位即可:

 

GraphQL的查詢也可以有註釋:

 

GraphiQL的智慧提示

GraphiQL是具有智慧提示的功能的。當你輸入一個字母之後,就是這種效果:

 

如果你什麼都不輸入,還想知道有哪些欄位,那麼就按Alt+空格

但是在windows上多少還是有些問題的,因為Alt+空格也會彈出瀏覽器的選單?。。。。

 

其實前面那個query關鍵字在這裡是可以省略的,點選prettify之後,就會把query關鍵字去掉;並且如果您的查詢格式比較亂的話,點選prettify也會對查詢進行格式化:

 

查詢引數

 在GraphQL裡,每個欄位都可以有自己的引數。

 直接看例子。下面這個例子裡,我想查詢登入名為facebook的倉庫所有者:

括號裡就是查詢引數,這個引數的作用就是過濾資料,返回login欄位等於facebook的倉庫所有者。

 

再看一個例子,這次我要查詢repository,引數是name,引數值是graphql,點選查詢:

注意,查詢語句裡有紅色波浪線。不出意外,返回的了錯誤。

(所有的錯誤請求的返回結果都是這個格式的)。

 

錯誤資訊裡告訴我們要查詢repository這個欄位,必須要提供owner這個引數,那麼我們就加上這個引數:

這次終於返回了正確的結果。

 

也可以再新增幾個欄位:

 

GraphQL Schema

上面我介紹了幾個查詢的例子,下面我介紹一下這個查詢的後臺工作原理。

上面這些欄位的設定是由GraphQL的schema來決定的。

  • Schema提供了你的資料中所有使用的物件型別。
  • 它制定了所有值的型別。

 

開啟Github的Graphiql,右側有個Docs按鈕,也就是文件:

每當我們定義了一個schema之後,文件就會自動生成。

 

開啟Docs,可以看到兩種操作型別

  • Query,查詢,也就是用來獲取資料的。
  • Mutation,變化,也就是用來更新資料的。

 

點選Query,進去後我們可以在這裡看見之前進行的那些查詢:

 

那麼就點選一下剛才的repository這個查詢:

可以看到這個查詢需要兩個引數:owner和name,型別都是字串。

 

再返回到Query,仔細看一下那些和欄位在一起的黃色字型的東西:

這些就是型別

在型別裡,有的是常見的型別:例如StringIntFloatBooleanID

 

輸入型別和返回型別

當定義schema的時候,我們也會相應的定義所允許的輸入型別,它們可以是引數型別或欄位型別。

輸入型別可以是:Int,Float,String,Boolean,Null,Enum,List,Object。

例如:

後邊的歎號,表示該引數是必須的。

 

冒號後邊的部分就是返回型別

 

當我們定義好Schema之後,文件就生成了,所以GraphQL是自我生成文件的

 

查詢Schema

除了看文件之外,你可以直接查詢schema,這點在我們不使用graphiql的時候尤其有用。

這個查詢裡,我們要查的是__schema欄位;然後是它下面的queryType欄位,queryType將會返回schema下所有的查詢;然後我再查詢queryType下的name和description,點選執行,就會看到右邊的結果:name是Query,描述是它是Github GraphQL介面的query root。

這個結果和文件裡的描述是一樣的:

下面再加上fields欄位看看:

這個結果的fields欄位就包括很多內容了:codeOfConduct,license等等。而這些就是root query所有支援的欄位。

 

查詢Type

除了查詢schema外,另一個有用的查詢就是Type的查詢。

例子,查詢Repository這個型別的相關資訊,查詢__type欄位,帶著引數name為Repository:

這個查詢結果也和文件裡的一致,我就不貼圖了。

 

別名

當我使用不同的引數來查詢兩個同樣的欄位的時候,會報錯的:

 

時就應該使用別名了。新增別名只需要在欄位前邊加上別名和冒號即可:

這回查詢就沒有錯誤了。

 

Fragment

上面的例子裡,graphql和aspnethome都查詢的是相同的幾個欄位。這樣的輸入就有點重複了,這時我們就可以使用Fragment。Fragement是可重用的欄位集合,它可以根據需要被包含在查詢裡。

上面的例子使用fragement以後就是這樣:

最下面是fragment的定義,使用fragment關鍵字,然後跟著自定義的名稱,它作用於Repository這個型別,大括號裡就是需要查詢的欄位。

在查詢裡使用fragment時需要用三個點"...",它的作用相當於js裡的展開操作符,把fragment裡面的欄位展開到相應的查詢裡。

fragment在GraphQL裡使用的非常多

 

今天先到這。

相關文章