同窗,GraphQL瞭解一下:基礎篇

實踐篇:GraphQL瞭解一下:實踐篇
進階篇:GraphQL進階篇: 揮手Redux不是夢前端

簡介

GraphQL由Facebook發起,其手機客戶端自2012年起,就全面採用了GraphQL查詢語言, 2015年, Facebook全面開源了第一份GraphQL規範。到目前爲止,在Twitter,Github,Pinterest,Shopify等大型網站也獲得了普遍的實踐。語言也從最初的js,擴展到java ,python,Go。且Apollo-client也逐漸作全了graphql生態。
GraphQL是一種用於 API 的查詢語言(規範),是一種協議而非存儲。GraphQL對你的API中的數據提供了一套易於理解的完整描述,使得客戶端可以準確地得到它須要的數據,並且沒有任何冗餘;
若是想在讀下面的知識以前,對GraphQL先有一個粗狂的認識,能夠登陸GitHub GraphQL API 站點,體會一下其使用,可點擊右側的Doc文檔查看接口定義。 java

clipboard.png

GraphQL出現的意義

clipboard.png
上面是一張咱們經常使用的Restful接口交互和引入GraphQL接口中間層的接口交互對比圖,在此以前,咱們先了解一下當前咱們所使用的Restful接口的痛點:python

  1. 冗餘字段大量返回;
  2. 渲染一個複雜的頁面須要發起多個請求;
  3. API定義文檔更新不及時;

相信上面的三點,在前端淌過水的你,必定是會有體會的。一個接口,同時用於h5頁面和web頁面的渲染源數據,但可能H5頁面只須要這些數據源的1/10,冗餘數據的返回浪費了流量,消耗了時間;因爲如今後端更推崇microservice,提供聚合服務的API被認爲沒有技術含量,因此咱們有時渲染一個關係複雜的頁面,須要請求5,6次,才能完整的渲染出一個頁面,這期間咱們還得去容錯,避免因其中某一個請求的失敗致使頁面沒法渲染的問題;API文檔更新不及時,相信這是最多見的吐槽,好好的靜態頁面寫完,並本身照着API文檔作完mock,等聯調時,接口返回的字段徹底不按API定義來,奔潰。
clipboard.png
上圖摘自GraphQL官網,其用簡單的三句話:描述你的數據(服務端),請求你所要的數據(客戶端),獲得可預測的結果。其隱藏的意思就是:react

  1. 服務端(或則中間層)須要描述全部可能的類型系統(Schema),有必定工做量;
  2. 按你所需請求你須要的數據,這就解決了不一樣客戶端,不一樣的渲染需求,都請求回一樣的數據源的痛點;
  3. 獲取多個資源只用一個請求,除了你能夠描述你某個請求須要返回那些字段,你還能夠定義這個請求須要返回那些數據。對應瀏覽器來說,只發送了一個請求,GraphQL服務端會根據請求定義將這些請求拆分,並最後再將數據拼裝返回回來;

聽起來是否是特別爽,那實現起來呢?git

零碎的GraphQL語法

基礎語法

其實GraphQL所須要學習的語法不多,大部分語法與咱們平時的語法一致,能夠經過官網詳細瞭解。首先,GraphQL是一門強類型語言,因此和咱們在數據庫定義一張表同樣,咱們須要定義每個屬性的類型.以下圖所示:github

clipboard.png

enum Episode {
      NEWHOPE
      EMPIRE
      JEDI
    }
    type Person{
         id: ID! 
         name: String!
         friends: [Person]
         appearsIn: [Episode]! 
    }

上面是一個簡單的類型定義,先是定義了一個枚舉,而後咱們定義了一個類型,類型中有四個屬性:id、 name、 friends、 appearsIn,其中id和name是標量類型,而friends是一個Person類型,這是一個嵌套類型,仔細想一想應該沒什麼毛病,畢竟你的朋友和你同樣,都是人;而appearsIn是一個枚舉類型,看起來仍是很熟悉的;
瞭解完類型,再瞭解一下Arguments和resolver,二者都是偏服務端一些,可是瞭解一下,對graphql的使用原理有進一步的認識;
對於一個Restful API來說,除了知道接口URL,咱們還須要知道接口的傳參定義,對於GraphQL其實也同樣,雖然URL只有一個,不一樣的接口經過type來區別,但傳參同Restful API同樣,體現了客戶端與服務端的交互。好比下面,查詢的目標是id = 2的用戶,獲取他的用戶名:web

Query{
        user(id: 2) {
            id
            userName
        }
    }

而在服務端定義一個接口時,咱們也須要去定義入參,主要從兩個方面,一是類型,二是其是否必填,好比下面這樣:
接口定義 數據庫

user: {
    type: UserType,
    args: {
      id: { type: GraphQLID }
    },
    resolve: (root, args, context, info) => {
      const { id } = args;
      return getUser(id);
    }
  }

查詢定義 編程

clipboard.png

上面的代碼只是定義了一個輸入屬性id,並未定義其是不是必填,因此當查詢時,若是沒有配置查詢id,查詢不會報錯,只會獲取一個爲null的空值結果。可是講道理的話,咱們但願這是一個必填項,因此咱們須要修改服務端的代碼,將id: { type: GraphQLID } 更換爲id: {type: new GraphQLNonNull(GraphQLID)},這句代碼的含義就表示id是一個類型爲ID的必填項,再次執行咱們的查詢能夠獲得下面的錯誤提示,提示id是一個必填的ID類型,同時右側也沒有獲取到爲空的查詢結果;後端

clipboard.png
在講上面Arguments時候,能夠零星的看到type中有一個resolve方法,其接收root, args, context, info四個參數。其中root表明這個type上父節點的resolve值(由於GraphQL支持嵌套查詢),args就是上面講的,context表在Resolver解析鏈中不斷傳遞的中間變量,和react的上下文類似,而info這個概念,是當前Query的AST對象,比較抽象,可是能夠經過查看info,獲取這個QUERY的編譯對象。這個方法也是後端服務編寫的重點部分,經常咱們能夠在這裏與已有的Restful API關聯起來。

核心概念

Schema能夠說是GraphQL最具核心的部分,其描述了整個接口向外暴露的形式;像Restful API,咱們會定義一個查詢全部人的接口url定義爲:/api/v1/user/getUsers,而查詢人具體信息的接口url爲:/api/v1/user/getUserById,而新增一我的員的接口url定義爲:/api/v1/user/createUser,前端人員調用起來很直觀。可是graphql是徹底不同的使用方式,其向前端暴露的url就一個像/api/graphql之類的,那這麼多接口怎麼區分呢?
clipboard.png

奧妙就是上面這張圖,一個graphql接口都有一個Schema定義,其定義三種操做方式:query(查詢),mutation(變動)和subscription(監聽)。再往下延伸,一個查詢中包含多個field,也就是多種不一樣的查詢,好比query user查詢人,query message查詢消息,query weather查詢天氣,經過這些就實現了Restful API使用多個url來達到不一樣操做的效果。看下面一張圖(使用最原生的graphql語言編寫,有助於理解):

clipboard.png

總結

這是一篇本身學習GraphQL期間,概括總結到的信息,本身感受是同如今的開發方式相比,須要在前端與Restful API之間增長一層GraphQL中間層,這確實增長了工做量,但看上面提到的語法,其編程仍是很是直觀易懂的,在業務不是那麼繁重的時候,仍是值得推廣的。在下一篇將會講到:實現一個GraphQL Server與在React應用中引入GraphQL

相關文章
相關標籤/搜索