現在越來越多的公司開始用GraphQL來建立API。我們獲取數據的方式發生了革命性的變化。
GraphQL的起源以及我們爲什麼要使用這種方法
GraphQL來自於facebook。facebook內部正在尋找一種讓他們的新聞推送在移動平臺上加載的更穩定的方法。
使用傳統REST API結構,新聞推送對多個API端點進行了多重調用,以便獲得所需的所有數據。但是這一路走來,API調用也會取到新聞推送那部分不需要的多餘數據。不僅如此,在收到數據之後,前端工程師還必須通過數據解析找到他們想要的片段。
facebook工程師想知道,“如果我們可以編寫指令語言,那麼我們可以在單個API請求中找到需要的所有信息?”
GraphSQL是工程師們努力的研究結果。首先它將數據庫中對象之間的關係映射到我們創建的一個圖表中。然後他們設計了一個指令語言來找到這些關係的映射。因此,它被命名爲“GraphSQL”。
通過添加查詢語言,GraphSQL API現在可以接受單個端點的所有接收請求。然後,他們取回並返回所請求的數據,並且只返回到所請求的數據。這樣將不再重複獲取用戶不使用的信息。
是一份規範而不是實現方法
最重要的是,Facebook決定開放源代碼GraphQL作爲一份規範。
這意味着它可以通過任何編程語言實現。只要實現以規定的方式分析指令得出它的框架,它就能很好地運行任何其他GraphQL應用程序。
事實上,現在每種主流編程語言中都有幾十種實現GraphQL的方法。
在本文中,我們將使用JavaScript編寫的GraphQL來實現,這是在任何語言中都適用的相同基本原則。您可以查看GraphQL實現的完整列表,以找到您最喜歡的語言。
基礎架構
開發一個功能良好的GraphQL API需要兩個部分:服務器和客戶端。服務器處理傳入的指令,解析這些指令,使用規定的規範來獲取數據,並通過JSON進行返回。
客戶端使您的應用程序能夠與服務器通信。雖然您只需向GraphQL端點發送簡單的POST請求,但是如果使用GraphQL客戶端來幫助發送指令,則可以獲得更好的使用效果。
構建GraphQL API可能比構建REST API更加的集中。然而,在速度和實際應用上的優點可以彌補它在複雜或高強度的應用程序運行的不足。
GraphQL是什麼樣的
我們API的目標是發送一個GraphQL指令並收到一個響應。我們一起來看看GraphQL大概是什麼樣的。
記住,GraphQL是它自己的語言。它並不是一種很難學習的語言,而且在很大程度上編寫指令是很直接的。讓我們想象一下,我們有一個包含了飛機和乘客信息的數據庫。在GraphQL中,我們可以這樣定義飛機:
{
flight(id: "1234") {
origin
destination
}
}
這是GraphQL所發出的:“給我飛機1234的始發地和目的地。”我們會收到這樣的迴應:
{
"data": {
"flight": {
"origin": "DFW",
"destination": "MKE"
}
}
}
提示:
我們收到正好都是我們指令所要求的內容,不多也不少。
我們還收到了與我們發送的原始指令完全相同的格式響應。這些是GraphQL API的標記。這是GraphQL如此快速和強大的原因。
不過,這並不是我們所能做的事情。我們想要得到這架飛機上的乘客信息,該怎麼做:
{
flight(id: "1234") {
origin
destination
passengers {
name
}
}
}
現在,GraphQL將向下掃描該航班與乘客之間的關係圖。我們會得到一份乘客名單反饋:
現在我們可以用一個API調用立即查看此航班上的所有乘客。
爲什麼Han、Luke和R2正在飛往國內,由於GraphSQL將數據分析爲圖形,我們也可以在其他方向進行掃描。
{
"data": {
"flight": {
"origin": "DFW",
"destination": "MKE",
"passengers": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "R2-D2"
}
]
}
}
}
現在我們可以看到飛機Luke記錄了什麼:
{
"data": {
"person": {
"passport_number": 78120935,
"flights": [
{
"id": "1234",
"date": "2019-05-24",
"origin": "DFW",
"destination": "MKE"
},
{
"id": "2621",
"date": "2019-07-05",
"origin": "MKE",
"destination": "DFW"
}
]
}
}
}
哇,他要在密爾沃基呆一個多月了!我想知道他在那裏幹什麼?
列一項清單
所以我們創建GraphQL API需要什麼?
選擇一個框架來實現GraphQL的服務器。我們會使用Express。
定義架構,以便GraphQL知道如何引導輸入的指令。
構造函數來處理指令,和告訴GraphQL返回到哪裏。
構造端點。
編寫獲取數據的客戶端指令。
然後,您可以使用GraphQL指令來向客戶端應用程序供電。本教程不會進入前端使用GraphSQL所有不同方式,但它與所有前端框架相兼容。
最終,GraphQL的大多數使用將涉及到與數據庫的對話。在本教程中,我們將不討論向Express添加數據庫和允許GraphQL查詢和更新該數據庫。這是一個完全不同的教程。
1.實現服務器
首先,需要爲API奠定基礎。您將需要安裝的Nodejs和NPM隨本教程從此處退出。
構建一個Barbones Express服務器。啓動NPM:
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (graphql-medium)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /home/bennett/Repos/graphql-medium/package.json:
{
"name": "graphql-medium",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this OK? (yes)
只需點擊Enter就可以跳過初始化過程。也可以回頭編輯Package.json。接下來,讓我們安裝Express、GraphQL和Express-GraphQL庫:
$ npm install express express-graphql graphql
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN [email protected] No description
npm WARN [email protected] No repository field.
+ [email protected]
+ [email protected]
+ [email protected]
added 53 packages from 38 contributors and audited 151 packages in 6.169s
found 0 vulnerabilities
現在,我們將創建一個名爲index.js的新文件,並在那裏創建一個新的barebones Express服務器:
// index.js
const express = require('express');
const app = express();
app.get('/', function(req, res) {
res.send('Express is working!')
});
app.listen(4000, function() {
console.log('Listening on port 4000')
});
嘗試運行節點index.js。您應該會看到一條“Listening on port4000”的消息,如果您訪問http://localhost:4000/,您將看到“Express正在工作”
添加GraphQL&DefineSchema我們已經安裝了GraphQLNPM包。現在可以運行這個程序了。
首先,我們需要導入必要的模塊:
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
接下來,我們將使用這些模塊。讓我們開始定義GraphQL API的結構。輸入的指令應該是什麼樣的?現在,讓我們定義一個HelloWorld模式,以獲取工作的事物:
let schema = buildSchema(`
type Query {
hello: String
}
`);
這個簡單的模式讓GraphQL知道,當有人發送查詢“Hello”時,我們將返回一個字符串。注意裏面的那些小後背(`)。這表明我們使用的是JavaScript模板文字。基本上,我們使用這些回退來告訴JavaScript,我們將要用另一種語言編寫GraphQL指令的語言。
3.解決指令
因此,當有人爲Hello提交指令時,我們知道我們將返回一個字符串。這是在我們的模式中定義的。現在,我們需要確切地告訴GraphQL它應該返回什麼字符串。根據輸入的指令確定要返回的數據是GraphQL中“解析器”的工作。在本例中,分析方法很簡單。我們將返回字符串“Hello world”。
return 'Hello world!';
但是,我們需要將該返回語句放在一個可以多次調用的函數中,無論何時有人在hello中編寫指令:
function() {
return 'Hello world!';
}
現在,hello可能不是我們實現的唯一指令的類型。未來,我們可能還包括其他功能的“端點”。因此,我們應該確保我們剛剛創建的這個函數映射到hello與我們API的所有其他部分一起,保存在一個對象中。
let root = {
hello: function() {
return 'Hello world!';
},
}
這是一個調用對象的公約,它可以保留所有解析器的原始數據,無論您需要什麼,都可以通過它得到。
4.設置一個端點
精明的讀者會注意到,我們在步驟2中導入了GraphqlHTTP,但我們還沒有使用它。現在是時候了。我們現在已經爲GraphSQLServer提供了一切。我們只需要通過URL端點提供它。在Express中,我們將創建一個新的路由來服務GraphSQLAPI
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
模式和原始數據指向步驟2和3中定義的變量。GraphSQL是一個有用的可視化工具,它與GraphSQL一起安裝。正如我們將在第二個中看到的,它很容易得出您的API是如何工作的。這是我們的GraphSQLServer源代碼的最終狀態。
運行程序&輸入一個指令
準備測試該程序!
用NPMindex.js啓動應用程序
轉到http://localhost:4000/GraphSQL您應該看到GraphSQL界面:
我們現在可以使用這個接口來確保我們的API正在工作!
讓我們寫一個指令。這個很簡單的。我們總是在大括號中寫我們的GraphSQL指令。然後,我們指定要提取的任何屬性所對應的模式對象。
在這種情況下,目前我們API中只有一個東西要提取:
{
hello
}
如果你點擊了提交按鈕,你將會看到:
{
"data": {
"hello": "Hello world!"
}
}
它正在工作!
添加更多的端點
向API添加端點就像在模式中定義新字段一樣簡單,然後將解析器函數添加到原始數據中。
您也可以讓指令逐漸變得複雜。下一步,我推薦這個來自官方文檔的引導building a dice rolling API。
GraphQL, FTW
GraphQL非常好用,它在應用中迅速成長。在未來的幾年裏,它有可能成爲一種無處不在的API技術。希望本指南爲您很好地介紹了可以在項目中使用GraphQL的原因和方法。在下面的評論中分享你的想法!我會看所有的回覆。