huhao0 2019-07-30
原文:https://medium.com/free-code-camp/give-it-a-....
译者:前端技术小哥
现在越来越多的公司开始用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更加的集中。然而,在速度和实际应用上的优点可以弥补它在复杂或高强度的应用程序运行的不足。
我们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调用立即查看此航班上的所有乘客。
为什么小小小黄正在飞往国内,由于GraphSQL将数据分析为图形,我们也可以在其他方向进行扫描。
{ "data": { "flight": { "origin": "DFW", "destination": "MKE", "passengers": [ { "name": "小明" }, { "name": "小黄" }, { "name": "小小" } ] } } }
现在我们可以看到飞机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的大多数使用将涉及到与数据库的对话。在本教程中,我们将不讨论向Express添加数据库和允许GraphQL查询和更新该数据库。这是一个完全不同的教程。
首先,需要为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 port 4000”的消息,如果您访问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指令的语言。
因此,当有人为Hello提交指令时,我们知道我们将返回一个字符串。这是在我们的模式中定义的。现在,我们需要确切地告诉GraphQL它应该返回什么字符串。根据输入的指令确定要返回的数据是GraphQL中“解析器”的工作。在本例中,分析方法很简单。我们将返回字符串“Hello world”。
return 'Hello world!';
但是,我们需要将该返回语句放在一个可以多次调用的函数中,无论何时有人在hello中编写指令:
function() { return 'Hello world!'; }
现在,hello可能不是我们实现的唯一指令的类型。未来,我们可能还包括其他功能的“端点”。因此,我们应该确保我们刚刚创建的这个函数映射到hello与我们API的所有其他部分一起,保存在一个对象中。
let root = { hello: function() { return 'Hello world!'; }, }
这是一个调用对象的公约,它可以保留所有解析器的原始数据,无论您需要什么,都可以通过它得到。
精明的读者会注意到,我们在步骤2中导入了GraphqlHTTP,但我们还没有使用它。现在是时候了。我们现在已经为GraphSQLServer提供了一切。我们只需要通过URL端点提供它。在Express中,我们将创建一个新的路由来服务GraphSQLAPI
app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: root, graphiql: true, }));
模式和原始数据指向步骤2和3中定义的变量。GraphSQL是一个有用的可视化工具,它与GraphSQL一起安装。正如我们将在第二个中看到的,它很容易得出您的API是如何工作的。这是我们的GraphSQLServer源代码的最终状态。
运行程序&输入一个指令
准备测试该程序!
用npm index.js
启动应用程序
转到http://localhost:4000/GraphSQL
您应该看到GraphSQL界面:
我们现在可以使用这个接口来确保我们的API正在工作!
让我们写一个指令。这个很简单的。我们总是在大括号中写我们的GraphSQL指令。然后,我们指定要提取的任何属性所对应的模式对象。
在这种情况下,目前我们API中只有一个东西要提取:
{ hello }
如果你点击了提交按钮,你将会看到:
{ "data": { "hello": "Hello world!" } }
它正在工作!
添加更多的端点
向API添加端点就像在模式中定义新字段一样简单,然后将解析器函数添加到原始数据中。
您也可以让指令逐渐变得复杂。下一步,我推荐这个来自官方文档的引导building a dice rolling API。
GraphQL非常好用,它在应用中迅速成长。在未来的几年里,它有可能成为一种无处不在的API技术。希望本文为您很好地介绍了可以在项目中使用GraphQL的原因和方法。