GraphQL入門指南

2021-03-02 51reboot運維開發

GraphQL is Facebook’s new query language for fetching application data in a uniform way.

GraphQL並不是一個面向圖資料庫的查詢語言,而是一個數據抽象層,包括數據格式、數據關聯、查詢方式定義與實現等等一攬子的東西。GraphQL也並不是一個具體的後端編程框架,如果將REST看做適合於簡單邏輯的查詢標準,那麼GraphQL可以做一個獨立的抽象層,通過對於多個REST風格的簡單的接口的排列組合提供更多複雜多變的查詢方式。與REST相比,GraphQL定義了更嚴格、可擴展、可維護的數據查詢方式。


GraphQL與之前Netflix出品的Falcor,都是致力於解決相同的問題:如何有效處理日益增長不斷變化的Web/Mobile端複雜的數據需求。筆者一直認為,REST原論文最大的功勞在於前後端分離與無狀態請求,而REST的資源化的請求方式只適合面向簡單的請求,對於具有複雜資源間關聯的請求就有點無能為力。關於這一點,筆者在之前的RARF系列中有過充分的討論。

GraphQL is a specification.

還是需要強調一點,引入GraphQL並不意味著要像之前從Struts遷移到SpringBoot一樣需要去修改你的真實的後端代碼,因此GraphQL可以看做一個業務邏輯層靈活有效地輔助工具。這一點也是GraphQL與原來的REST API最大的差別,舉例而言:

{  latestPost {    _id,    title,    content,    author {      name    },    comments {      content,      author {        name      }    }  }}

這是一個很典型的GraphQL查詢,在查詢中指明了需要返回某個Blog的評論與作者信息,一個典型的返回結果譬如:

{  "data": {    "latestPost": {      "_id": "03390abb5570ce03ae524397d215713b",      "title": "New Feature: Tracking Error Status with Kadira",      "content": "Here is a common feedback we received from our users ...",      "author": {        "name": "Pahan Sarathchandra"      },      "comments": [        {          "content": "This is a very good blog post",          "author": {            "name": "Arunoda Susiripala"          }        },        {          "content": "Keep up the good work",          "author": {            "name": "Kasun Indi"          }        }      ]    }  }}

而如果採用REST API方式,要麼需要前端查詢多次,要麼需要去添加一個新的接口,專門針對前端這種較為特殊的請求進行響應,而這樣又不可避免地導致後端代碼的冗餘,畢竟很有可能這個特殊的請求與返回哪天就被廢了。

ReferenceTutorials & DocsMechanism:原理介紹Practices & ResourcesComparison:框架對比CollectionQuick StartOfficial Quick Start:官方的簡單的Quick Start教程Setup

首先創建項目文件夾:

mkdir graphql-democd graphql-demo

然後使用npm安裝必要的依賴:

npm init -fnpm install graphql express express-graphql --save

Data

作為一個簡單的數據伺服器,我們僅使用最簡單的JSON文件作為數據源:

{  "1": {    "id": "1",    "name": "Dan"  },  "2": {    "id": "2",    "name": "Marie"  },  "3": {    "id": "3",    "name": "Jessie"  }}

Server

一個簡單的GraphQL伺服器需要創建Scheme以及支持的查詢:

// Import the required librariesvar graphql = require('graphql');var graphqlHTTP = require('express-graphql');var express = require('express');// Import the data you created abovevar data = require('./data.json');// Define the User type with two string fields: `id` and `name`.// The type of User is GraphQLObjectType, which has child fields// with their own types (in this case, GraphQLString).var userType = new graphql.GraphQLObjectType({  name: 'User',  fields: {    id: { type: graphql.GraphQLString },    name: { type: graphql.GraphQLString },  }});// Define the schema with one top-level field, `user`, that// takes an `id` argument and returns the User with that ID.// Note that the `query` is a GraphQLObjectType, just like User.// The `user` field, however, is a userType, which we defined above.var schema = new graphql.GraphQLSchema({  query: new graphql.GraphQLObjectType({    name: 'Query',    fields: {      user: {        type: userType,        // `args` describes the arguments that the `user` query accepts        args: {          id: { type: graphql.GraphQLString }        },        // The resolve function describes how to "resolve" or fulfill        // the incoming query.        // In this case we use the `id` argument from above as a key        // to get the User from `data`        resolve: function (_, args) {          return data[args.id];        }      }    }  })});express()  .use('/graphql', graphqlHTTP({ schema: schema, pretty: true }))  .listen(3000);console.log('GraphQL server running on http://localhost:3000/graphql');

然後使用node命令啟動伺服器:

node index.js

如果你直接訪問http://localhost:3000/graphql會得到如下反饋:

{  "errors": [    {      "message": "Must provide query string."    }  ]}

Queries

按照如下方式可以創建一個簡單的根據ID查詢用戶的姓名,從中可以看出基本的GraphQL的查詢的樣式,就是一個JSON的Key-Value對,鍵值就是查詢值:

{  user(id: "1") {    name  }}

返回數據是:

{  "data": {    "user": {      "name": "Dan"    }  }}

如果你希望以GET方式進行查詢,可以移除所有的空格,即得到如下方式的請求:

http://localhost:3000/graphql?query={user(id:"1"){name}}

Another First GraphQL Server:另一個Step By Step的介紹Setup an HTTP Server:構建一個HTTP伺服器

注意,GraphQL定義了一種通用的數據查詢語言,並不一定要基於HTTP協議,不過目前絕大部分應用伺服器的交互協議都是HTTP,因此這裡也是基於Express以及GraphQL的JavaScript實現 構建一個簡單的GraphQL伺服器。

$ mkdir graphql-intro && cd ./graphql-intro$ npm install express --save$ npm install babel --save$ touch ./server.js$ touch ./index.js

而核心的服務端代碼為:

// index.js// by requiring `babel/register`, all of our successive `require`s will be Babel'drequire('babel/register');require('./server.js');// server.jsimport express from 'express';let app  = express();let PORT = 3000;app.post('/graphql', (req, res) => {  res.send('Hello!');});let server = app.listen(PORT, function () {  let host = server.address().address;  let port = server.address().port;  console.log('GraphQL listening at http://%s:%s', host, port);});

直接使用Node命令即可以啟動伺服器:

$ node index.jsGraphQL listening at http://0.0.0.0:3000

可以用Curl進行簡單的測試:

$ curl -XPOST http://localhost:3000/graphqlHello!

創建一個Schema

現在我們已經創建了一個簡單的HTTP Server可以進行交互,下面我們就要為該Server添加GraphQL查詢的解析的支持。首先回顧下一個基本的GraphQL的查詢請求如下:

query getHighScore { score }

該查詢意味著某個GraphQL的客戶端希望獲取getHighScore域的score子域的信息,Fields就是客戶端要求GraphQL返回的數據說明,一個Fields也可以包含參數,譬如:

query getHighScores(limit: 10) { score }

而我們的GraphQL Server首先需要知道應該如何去解析這樣的請求,即需要去定義Schema。構建一個Schema的過程有點類似於構建RESTful的路由樹的過程,Schema會包含Server可以返回給前端的Fields以及響應中的數據類型。GraphQL中是採取了靜態數據類型,因此Client可以依賴於其發起請求時聲明的數據類型。首先我們聲明使用Schema所需要的依賴項:

$ npm install graphql --save$ npm install body-parser --save$ touch ./schema.js

然後我們創建一個GraphQLSchema實例,一般來說我們會將配置放入一個單獨的文件夾中:

// schema.jsimport {  GraphQLObjectType,  GraphQLSchema,  GraphQLInt} from 'graphql/lib/type';let count = 0;let schema = new GraphQLSchema({  query: new GraphQLObjectType({    name: 'RootQueryType',    fields: {      count: {        type: GraphQLInt,        resolve: function() {          return count;        }      }    }  })});export default schema;

該Schema的定義用通俗地語言表達即是針對查詢會返回一個RootQueryType的對象,而每個RootQueryType對象會包含一個整型的count域。

Connect the Schema

在定義好了Schema之後,我們就需要將其應用到HTTP Server中:

import express from 'express';import schema from './schema';// new dependenciesimport { graphql } from 'graphql';import bodyParser from 'body-parser';let app  = express();let PORT = 3000;// parse POST body as textapp.use(bodyParser.text({ type: 'application/graphql' }));app.post('/graphql', (req, res) => {  // execute GraphQL!  graphql(schema, req.body)  .then((result) => {    res.send(JSON.stringify(result, null, 2));  });});let server = app.listen(PORT, function () {  var host = server.address().address;  var port = server.address().port;  console.log('GraphQL listening at http://%s:%s', host, port);});

所有針對/graphql的查詢都會在定義好的Schema下執行,這裡我們默認的返回count值,還是使用Curl進行簡單的調試可以得到:

$ node ./index.js // restart your server// in another shell$ curl -XPOST -H "Content-Type:application/graphql"  -d 'query RootQueryType { count }' http://localhost:3000/graphql{ "data": {   "count": 0 }}

Introspect the Server:獲取Server定義的Schema信息

實際上,GraphQL Server也可以返回其定義好的Schema信息:

$ curl -XPOST -H 'Content-Type:application/graphql'  -d '{__schema { queryType { name, fields { name, description} }}}' http://localhost:3000/graphql{ "data": {   "__schema": {     "queryType": {       "name": "RootQueryType",       "fields": [         {           "name": "count",           "description": null         }       ]     }   } }}

其使用的查詢實際上就是這個樣子:

{ __schema {   queryType {     name,     fields {       name,       description     }   } }}

實際上,我們也可以為每個定義的域添加譬如description, isDeprecated, 以及 deprecationReason這樣的描述信息,譬如:

let schema = new GraphQLSchema({  query: new GraphQLObjectType({    name: 'RootQueryType',    fields: {      count: {        type: GraphQLInt,        // add the description        description: 'The count!',        resolve: function() {          return count;        }      }    }  })});

那麼返回的新的元信息就是:

$ curl -XPOST -H 'Content-Type:application/graphql'  -d '{__schema { queryType { name, fields { name, description} }}}' http://localhost:3000/graphql{ "data": {   "__schema": {     "queryType": {       "name": "RootQueryType",       "fields": [         {           "name": "count",           "description": "The count!"         }       ]     }   } }}

Add a Mutation:GraphQL中支持增刪改

上文中所講的都是基於GraphQL定義一個查詢方式,而GraphQL也是支持對於數據的增刪改,這在GraphQL中稱為mutations。Mutations也是一個域,其主要是為了指明某個請求打來的Side Effects,因此大部分的語法還是一致的。Mutations也是需要提供一個返回值的,主要是為了返回你改變的值以供驗證修改是否成功。

let schema = new GraphQLSchema({  query  mutation: new GraphQLObjectType({    name: 'RootMutationType',    fields: {      updateCount: {        type: GraphQLInt,        description: 'Updates the count',        resolve: function() {          count += 1;          return count;        }      }    }  })});

對應的查詢方式就是:

$ curl -XPOST -H 'Content-Type:application/graphql' -d 'mutation RootMutationType { updateCount }' http://localhost:3000/graphql{ "data": {   "updateCount": 1 }}

GraphiQL

Reboot 課程升級了:三個課程均有升級,全新開班日期已定。

「點擊原文」或回復「課程」,即可獲取課程表和開班時間。歡迎諮詢 QQ:279312229


於Reboot

專注於網際網路運維開發分享、交流,讓更多的運維工程師更加專注於自動化,為國內公有雲開發、監控、運維貢獻自己的力量。這裡聚集著國內一線網際網路工程師,樂於分享與交流 。發現文章不錯的話請關注我們。

Reboot 官方QQ交流群:238757010

諮詢 QQ:279312229 

相關焦點

  • GraphQL 從入門到實踐
    正文從這開始~~本文首先介紹了 GraphQL,再通過 MongoDB + graphql + graph-pack 的組合實戰應用 GraphQL,詳細闡述如何使用 GraphQL 來進行增刪改查和數據訂閱推送,並附有使用示例,邊用邊學印象深刻~0. 什麼是 GraphQLGraphQL 是一種面向數據的 API 查詢風格。
  • GraphQL 入門看這篇就夠了
    graphql + graph-pack 的組合實戰應用 GraphQL,詳細闡述如何使用 GraphQL 來進行增刪改查和數據訂閱推送,並附有使用示例,邊用邊學印象深刻~如果希望將 GraphQL 應用到前後端分離的生產環境,請期待後續文章。
  • GraphQL 簡介:原理及其使用
    新建一個名為 graphql-with-nodejs 的文件夾,進入項目文件夾並運行 npm init 來創建 NodeJS 項目,終端命令如下:cd graphql-with-nodejsnpm init安裝依賴項使用以下命令安裝 Express:npm install express
  • GraphQL|一種配得上凡爾賽的API框架
    在知道答案之前,我們先來了解以下graphql。以下是graphql的官方站:https://graphql.cn/通過官方的實例,我們可以知道,graphql的主要功能,是進行API測試,與其他的API測試工具相比,graphql有幾個優勢:1、graphql可以通過圖形化界面的方式,在同一個界面上交互式地進行API數據測試,
  • GraphQL 實戰篇之前端Vue+後端
    安裝npm i --save @nestjs/graphql graphql-tools graphql apollo-server-express註冊// app.module.tsimport { Module } from '@nestjs/common
  • GraphQL 概念與測試(下):graphy測試框架
    "core": { "business_type": "", "is_main": false, "owner": "" }, "distribute": { "items": [] } } ] }}我們會發現:graphql
  • GraphQL 基礎實踐
    將它安裝到我們的項目中:npm install apollo-server-core graphql --save編寫中間件runHttpQuery主要接受兩個參數,第一個是 GraphQLServerOptions,這個我們可以不需要配置,留空數組即可;第二個是HttpQueryRequest對象,我們至少需要包含 methods,options以及query,
  • 【超詳細教程】如何使用TypeScript和GraphQL開發應用
    fantingshengdeMacBook-Pro:graphql-typescript fantingsheng$ yarn inityarn init v1.12.3question name (graphql-typescript):question version (1.0.0):question description: for study
  • GraphQL 值得了解一下
    本文參考資料:https://medium.com/javarevisited/basic-functionalities-of-graphql-every-developer-should-know-71347d7fab08
  • 如何使用GraphQL-進階教程:客戶端
    在 Xcode 中,可以使用 助理編輯器(Assistant Editor) 來同時處理視圖控制器和 graphql 代碼。前端記事本,不定期更新,歡迎關注!
  • Netflix 聯邦 GraphQL 平臺的實現過程及經驗教訓
    https://netflixtechblog.com/how-netflix-scales-its-api-with-graphql-federation-part-2-bbe71aaec44a
  • 如何使用GraphQL-基礎教程:介紹
    但是中文目前沒有很好的成套的入門教程,官網中文文檔看的我頭大,自學的過程中發現—— How to GraphQL 系列教程 ——寫的很明白,對於入門者來說比官網強得多,現將它基礎系列、進階系列和客戶端系列翻譯成中文輸出型學習一波。
  • 【歸納綜述】Graph Neural Network: An Introduction Ⅰ
    作者:劉浚嘉地址:https://www.zhihu.com/people/JunjiaLiu本文根據以下三篇綜述,旨在入門 Graph Neural Networks:A Comprehensive Survey on Graph Neural Networks | 2019 Janhttps://arxiv.org/pdf/1901.00596
  • 分分鐘將 REST 轉換為 GraphQL
    這個指南教你在不修改任何代碼的情況下,完成從 REST 到 GraphQL 的遷移。這樣,GraphQL 就能讓你的 REST 真正休息一下了!GraphQL 的支持者在宣傳推廣 GraphQL 方面已經做得非常好了。
  • Awesome Knowledge Graph : 知識圖譜資源匯總
    項目地址訪問 https://github.com/husthuke/awesome-knowledge-graph 可以獲取到最新版本的這個倉庫。通過學習視頻課程,可以快速入門,了解核心技術方向。想研究知識圖譜,或求職面向這個方向的,可以參加各類評測競賽,既是鍛鍊,也是自己能力的證明。
  • 圖論Graph theory
    Refer to the glossary of graph theory for basic definitions in graph theory., known as random graph theory, which has been a fruitful source of graph-theoretic results.
  • 【GCN】圖卷積網絡(GCN)入門詳解
    其中圖卷積網絡就非常熱門,我找到了一篇教程:圖卷積網絡(GCN)新手村完全指南, 想著藉此走出新手村,結果因為個人資質有限,簡直成了勸退文,看完了之後還是沒有非常的明白,所以決定自己寫一篇入門介紹。當然這篇文章介紹得非常好,我也參考了很多,所以我會引用很多其中的公式,加上相關的推導補充。本文主要分為兩部分,第一部分介紹什麼是GCN,第二部分將進行詳細的數學推導。
  • 河流圖(Stream graph)
    河流圖(Stream graph).❝河流圖(Streamg raph),有時候也叫做「主題河流圖」(Theme River),是堆積面積圖的一種變形,通過「流動」的形狀來展示不同類別的數據隨時間的變化情況。
  • CTF入門指南 | 內附教程分享
    都要學的內容:Windows基礎、Linux基礎、計算機組成原理、作業系統原理、網絡協議分析A方向:IDA工具使用(fs插件)、逆向工程、密碼學、緩衝區溢出等B方向:Web安全、網絡安全、內網滲透、資料庫安全等 前10的安全漏洞推薦書:A方向:RE for BeginnersIDA Pro權威指南
  • 深度學習中不得不學的Graph Embedding方法
    在這樣的背景下,對圖結構中間的節點進行表達的graph embedding成為了新的研究方向,並逐漸在深度學習推薦系統領域流行起來。阿里的Graph Embedding方法EGES2018年阿里公布了其在淘寶應用的Embedding方法EGES(Enhanced Graph Embedding with Side Information),其基本思想是在DeepWalk生成的graph embedding基礎上引入補充信息。