記一次經過c#運用GraphQL調用Github api


1、Graphql是什麼

  最近在折騰使用Github api作個微信小程序練練手,本篇文章就是在這個過程當中記錄。html

  直接先看下GraphQL的語法風格,感覺一下:前端

query {
  repository(owner:"octocat", name:"Hello-World") {
      id
  }
}複製代碼

  這是最最最簡單的一個運用示例,效果上等價於http://graphqlapi.xxx.com/query/repository?owner=octocat&name=Hello-World ,返回的內容格式是這樣:node

複製代碼
{
  "data": {
    "repository": {
      "id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5"
    }
  }
}複製代碼
複製代碼

  再看下稍微複雜點的查詢方式:git

複製代碼
query {
  repository(owner:"octocat", name:"Hello-World") {
    issues(last:20, states:CLOSED) {
      edges {
        node {
          title
          url
          labels(first:5) {
            edges {
              node {
                name
              }
            }
          }
        }
      }
    }
  }
}複製代碼
複製代碼

  這是一個多級對象嵌套的查詢,這裏就不繼續展開了。關於egde和node在下文會有少量講解。對GraphQL有興趣進行更深刻了解的能夠自行研究學習,我本身也是剛入門,不坑你們了:),官網是graphql.org/(這個可能打不開,能夠打開國內的地址graphql.cn),Facebook發佈的規範在 facebook.github.io/graphql/Oct…github

  GraphQL 既是一種用於 API 的查詢語言也是一個知足你數據查詢的運行時。GraphQL 對你的 API 中的數據提供了一套易於理解的完整描述,使得客戶端可以準確地得到它須要的數據,並且沒有任何冗餘,也讓 API 更容易地隨着時間推移而演進,還能用於構建強大的開發者工具。小程序

2、.net下如何運用GraphQL

  因爲我須要作一個定時任務將github上的數據定時拉到本地,因此天然的選擇了後端處理的方式。找了一下.net下的GraphQL客戶端,用了這個graphql-client。代碼以下:c#

複製代碼
var heroRequest = new GraphQLRequest
                {
                    Query = graphql   //這裏填寫query的內容。
                };

var graphQLClient = new GraphQLClient("https://api.github.com/graphql");

graphQLClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Safari", "537.36"));   
//上面這行很關鍵,UserAgent必定要寫上,要否則會出現403錯誤,花了很久才找到這個問題。
graphQLClient.DefaultRequestHeaders.Add("Authorization", "bearer token");   //這裏的token是個佔位,實際須要在Github上生成。
var graphQLResponse = graphQLClient.PostAsync(heroRequest).Result;複製代碼
複製代碼

  關於token的生成以及其它的一些環境準備工做,在github上有詳細的描述,參見:developer.github.com/v4/guides/f…後端

  重要的事情說3遍:UserAgent必定要寫上!! UserAgent必定要寫上!! UserAgent必定要寫上!!微信小程序

3、運用GraphQL調用Github api

   Github提供的API和相關文檔在developer.github.com/v4/ 右側的目錄樹上,此次筆者須要拉取github的大量repository庫,因此用到的search接口(可是很奇怪,這個接口在文檔中並無列出來,也不知道爲何)。建議你們能夠先在Github提供的explorer中先測試和驗證,OK了在把代碼寫到實際的項目中。api

  接着,筆者在實現本身須要的功能時又學習了2個概念,才能正常開展下面的工做。第一個是edge與node的概念,edge能夠理解爲一個分頁對象,其中除了包含實際的數據外還有一個cursor(返回的每條數據的惟一標識,若是要分頁的話用獲得這個數據,配合before與after關鍵字來使用)字段,實際數據就是用node表示的。

  另外GraphQL是強類型的,因此當筆者用到的search返回的結果並非一個明確的數據對象時,先須要經過node下的__typename字段來得到實際的對象是什麼。代碼以下:

複製代碼
query {
  search(query:"language:c#",type:REPOSITORY,first:1){
    edges{
      cursor,
      node{
        __typename
      }
    }
  }
}複製代碼
複製代碼

  獲得的結果是:

複製代碼
{
  "data": {
    "search": {
      "edges": [
        {
          "cursor": "Y3Vyc29yOjE=",
          "node": {
            "__typename": "Repository"
          }
        }
      ]
    }
  }
}複製代碼
複製代碼

  獲得的實際的數據對象是Repository以後,經過查閱Github Api的文檔獲得該對象有哪些字段,而且從中選擇須要的字段便可。這個就是GraphQL的設計自然優點之一,按需獲取。單在接下去運用的時候又須要引入一個新的概念fragment,這個能夠理解爲一個模板,經過這個模板來向服務端指明須要獲取的數據字段。代碼以下:

複製代碼
fragment repFragment on Repository {
  name,
  forkCount,
  url,
  createdAt,
  updatedAt,
  licenseInfo{  //對象嵌套
    nickname    //licenseInfo的nickname字段
  },
  stargazers{   //對象嵌套
    totalCount  //stargazers的totalCount字段
  }
}

query {
  search(query:"language:c#",type:REPOSITORY,first:100){
    edges{
      cursor,
      node{
        __typename
        ...repFragment
      }
    }
  }
}複製代碼
複製代碼

  好了,這樣就獲得我須要的結果了。

  下面附上筆者作的Demo:github.com/ZacharyFan/…,其中的token在配置文件中自行替換便可。

4、結語

  最後附帶提一下,GraphQL的出現,主要的場景仍是在於賦能前端開發,賦予了前端開發者自由組織和定製請求數據的能力。這是一個將先後端分離後的界限偏向前端的框架,因此直接在前端經過GraphQL訪問後端數據是我的比較推崇的方式。目前前端很是火熱的GraphQL框架也很多,主流的就是下面2個: apollo(https://github.com/apollographql/apollo-client)relay(https://github.com/facebook/relay)

  GraphQL雖好,可是要真正在中大型項目中運用GraphQL,還有有很大的困難的,服務端須要支持到GraphQL的規範格式進行數據輸出,我認爲須要付出的成本可不小。哪怕的架設一層中間層,也須要解決諸如分發、聚合和性能等問題。

做者:Zachary_Fan
出處:www.cnblogs.com/Zachary-Fan…

若是你想及時獲得我的自寫文章的消息推送,歡迎掃描下面的二維碼~。

相關文章
相關標籤/搜索