眾所周知RESTful API是目前最流行的軟體架構風格之一,它主要用於客戶端和伺服器互動類的軟體。基於這個風格設計的軟體可以更簡潔,更有層次,更易於實現快取等機制。
RESTful的優越性是毋庸置疑的,不過GraphQL也可以作為一種補充,讓你的服務既支援RESTful的http呼叫,也容許客戶端透過GraphQL支援的宣告式語法呼叫服務。
本篇文章並不想對比RESTful和GraphQL孰輕孰重,或者那種方式更好,相關比較可以參考GraphQL的前世今生。本文旨在介紹如何在ASP.NET Core應用中引入GraphQL,讓你的應用既支援RESTFul,也能支援GraphQL。
Web應用程式是如何工作的
如果說一個Service能夠提供一個功能,那麼我們就可以給Service一個輸入,從而得到一個輸出。

如果將若干個Service組合在一起形成一個應用程式,那麼這個應用程式就可以提供若干個能力,當一個框架分別就輸入和輸出進行統一的約定和規範時,也就是人們常說的SOAP,RESTful等技術。

對於RESTful來說,輸入就是Http request,輸出是一個json格式的字串。而Web應用程式框架在做什麼?根據某個輸入(request),找到對應的controller, 擊中合適的action,同時將Request系結為action方法的引數,最後將結果格式化為json字串並輸出。

GraphQL就是跟Web框架同一級別的技術,只不過輸入(input)不再是Http request,而是GraphQL特有的語法結構,輸出仍然為json字串。

GraphQL能夠做些什麼
既然GraphQL是一種可以代替RESTful的技術,那麼你一定很想知道他是怎麼做到的。 如果能用一句話總結那就是: GraphQL是一種API資源的查詢語言。GraphQL透過下麵的三種型別來滿足使用者的需求:
1. 查詢
我們都知道使用者的請求可以分為兩類:Query和Command,Query用於查詢資源,呼叫一次和多次都不會影響資源的狀態,一個簡單的查詢如下:
query {
hero {
id
name
}
}
上面的查詢語言可以理解為:查詢hero資源的”id”和”name“屬性
2. mutation
所謂mutation就是Command,意味著該使用者請求能夠改變服務端的狀態,一個簡單的mutation如下:
mutation ($human:HumanInput!) {
createHuman(human: $human) {
id
name
}
}
variables: {
"human": {
"name": "Boba Fett",
"homePlanet": "Kamino"
}
}
上面的mutation可以理解為建立一個humman物件,輸入物件是一個$human變數,最後把建立物件的`”id”和”name”屬性查詢出來。可以看出mutation一般都要配合一個變數使用,變數需要在”variables”中單獨定義。
3. Subscriptions
Subscriptions用於提供類似websocket的功能,GraphQL Server是一個實現了Apollo GraphQL訂閱協議的.NET Core伺服器. 下麵的例子需要同時開啟兩個瀏覽器視窗:
Subscription使用者訂閱聊天訊息:
subscription MessageAdded {
messageAdded {
from { id displayName }
content
}
}
Mutation使用者新增聊天內容:
mutation AddMessage($message: MessageInputType!) {
addMessage(message: $message) {
from {
id
displayName
}
content
}
}
variables:
{
"message": {
"content": "Message",
"fromId": "1"
}
}
GraphQL是如何實現的
我在用每一個開源框架或者類庫時都習慣於先瀏覽原始碼,瞭解整個原始碼的大概結構和實現。下麵的過程以一個簡單的查詢為例,分析GraphQL的實現原理:
{
query test {
user{
age
}
}
}
透過graphQL browser IDE傳送請求:GrpahQL處理的整個過程如下:

1.客戶端將上面的GraphQL query透過http傳送到服務端
curl 'http://localhost:5000/graphql' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: http://localhost:5000' --data-binary '{"query":"# Write your query or mutation here\nquery test{\n user{\n age\n }\n}\n"}' --compressed
2. 整個Request以json的格式傳送到了服務端,服務端將Request反序列化為GraphQLRequest型別:
public class GraphQLRequest
{
[JsonProperty("query")]
public string Query { get; set; }
[JsonProperty("variables")]
public JObject Variables { get; set; }
[JsonProperty("operationName")]
public string OperationName { get; set; }
public Inputs GetInputs()
{
return GraphQLRequest.GetInputs(this.Variables);
}
}
針對上面的例子,實際上只有string Query屬性被反序列化為””# Write your query or mutation here\nquery test{\n user{\n age\n }\n}\n”“
3.服務端解析Query,解析Query的過程是一個語法分析的過程,透過Paser將Query解析為AST:
var source = new Source(body);
var result = _parser.Parse(source);
Parse後的結果是一個Document類:
public class Document : AbstractNode
{
public string OriginalQuery { get; set; }
public Operations Operations { get; }
public Fragments Fragments { get; }
}
本例的Query將會被解析為一個Operations,一個Operations將包含若干個有層次結構的Operation,解析Query的目的是為了知道客戶端要查詢user.Age這個屬性。
4.有了一個Parse後的Document,接下來的工作將有DocumentExecuter來完成,DocumentExecuter定義了整個呼叫服務端資源的流程:
public async Task ExecuteAsync(ExecutionOptions options)
{
//1. 列印開始時間
//2. Parse Document
//3. 驗證Document是否是一個合法的GrapQL語法請求
//4. 在流程的各個階段執行Listener,用於在不同的時機切入程式碼,類似於ASP.NET Core中的Filter
//5. 選擇合適的執行策略
//6. 執行服務端資源
//7. 輸出Response
}
以上就是GraphQL在.NET Core中的實現原理分析,下一篇將透過一個hello world級別的例子演示如何讓你的ASP.NET應用程式支援GraphQL.
原文地址:https://www.cnblogs.com/xiandnc/p/10398505.html
.NET社群新聞,深度好文,歡迎訪問公眾號文章彙總 http://www.csharpkit.com 
知識星球
