讓ASP.NET Core支持GraphQL之-GraphQL的實現原理

衆所周知RESTful API是目前最流行的軟件架構風格之一,它主要用於客戶端和服務器交互類的軟件。基於這個風格設計的軟件能夠更簡潔,更有層次,更易於實現緩存等機制。
RESTful的優越性是毋庸置疑的,不過GraphQL也能夠做爲一種補充,讓你的服務既支持RESTful的http調用,也允許客戶端經過GraphQL支持的聲明式語法調用服務。
本篇文章並不想對比RESTful和GraphQL孰輕孰重,或者那種方式更好,相關比較能夠參考GraphQL的前世此生。本文旨在介紹如何在ASP.NET Core應用中引入GraphQL,讓你的應用既支持RESTFul,也能支持GraphQL。html

Web應用程序是如何工做的

若是說一個Service可以提供一個功能,那麼咱們就能夠給Service一個輸入,從而獲得一個輸出。
java

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

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

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

GraphQL可以作些什麼

既然GraphQL是一種能夠代替RESTful的技術,那麼你必定很想知道他是怎麼作到的。 若是能用一句話總結那就是: GraphQL是一種API資源的查詢語言。GraphQL經過下面的三種類型來知足用戶的需求:json

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"中單獨定義。websocket

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<ExecutionResult> 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.

相關文章
相關標籤/搜索