一、Graphql是什麼
最近在折騰使用Github api做個微信小程式練練手,本篇文章就是在這個過程中記錄。
直接先看下GraphQL的語法風格,感受一下:
query {
repository(owner:"octocat", name:"Hello-World") {
id
}
}複製程式碼
這是最最最簡單的一個運用示例,效果上等價於http://graphqlapi.xxx.com/query/repository?owner=octocat&name=Hello-World ,返回的內容格式是這樣:
再看下稍微複雜點的查詢方式:
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…。
GraphQL 既是一種用於 API 的查詢語言也是一個滿足你資料查詢的執行時。GraphQL 對你的 API 中的資料提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的資料,而且沒有任何冗餘,也讓 API 更容易地隨著時間推移而演進,還能用於構建強大的開發者工具。
二、.net下如何運用GraphQL
由於我需要做一個定時任務將github上的資料定時拉到本地,所以自然的選擇了後端處理的方式。找了一下.net下的GraphQL客戶端,用了這個graphql-client。程式碼如下:
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一定要寫上!!
三、運用GraphQL呼叫Github api
Github提供的API和相關文件在developer.github.com/v4/ 右側的目錄樹上,這次筆者需要拉取github的大量repository庫,所以用到的search介面(但是很奇怪,這個介面在文件中並沒有列出來,也不知道為什麼)。建議大家可以先在Github提供的explorer中先測試和驗證,OK了在把程式碼寫到實際的專案中。
接著,筆者在實現自己需要的功能時又學習了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在配置檔案中自行替換即可。
四、結語
最後附帶提一下,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…
如果你想及時得到個人自寫文章的訊息推送,歡迎掃描下面的二維碼~。