5 分钟内理解 GraphQL
GraphQL 一经推出便迅速在互联网上迅速传播,如同流行病般蔓延。GraphQL 彻底改变了人们的工作方式,并将继续在各个领域持续发展。如果您有五分钟时间,我将为您详细讲解所有您需要了解的内容。
曾几何时
到2012年,全球手机普及率已达到惊人的水平。这股入侵浪潮席卷全球,那些未能及时调整自身产品的公司将面临风险。当时,Facebook 就面临风险。
Facebook 主要是一家网络公司。因此,他们使用 web-view 将其 iOS 应用做得像个网站。很快,他们意识到 web-view 当时很糟糕。于是,他们决定完全用原生应用重做,以提供更好的用户体验。然而,他们很快就遇到了另一个瓶颈。
现有架构无法正常工作。主要是因为现有 REST API 的端点无法灵活处理数据。嵌套数据需要多次往返不同的端点,导致速度缓慢且不一致。大多数查询不需要部分有效负载,从而导致不必要的数据传输。最重要的是,处理如此多的 HTTP 调用对 Facebook 来说非常繁琐。
就在这种恶劣的环境下,2012年2月,Lee Byron、Dan Schafer和Nick Schrock在 Facebook 的一个角落里预定了一些工作站。
很快,我们的三位开发人员就开发出了 GraphQL 的第一个原型,当时名为 SuperGraph。2012 年 8 月,GraphQL 随新的 Facebook 原生应用投入生产。2015 年,第一个公开版本在互联网上发布。如今,当你浏览 Facebook 信息墙时,GraphQL 依然清晰可见。但他们是如何解决这个不仅影响 Facebook,而且影响整个行业的问题的呢?
什么是 GraphQL?
GraphQL 是一种用于 API 的数据查询语言。QL 与 SQL 类似,代表查询语言 (Query Language)。GraphQL允许以简单、灵活且非常精确的方式操作数据。GraphQL既不是编程语言,也不是框架。GraphQL 是一种实现 API 的规范。具体来说,它看起来像这样。
要求
{
pokemons {
name,
abilities {
name,
damage,
accuracy,
mana,
type
}
}
}
回复
{
"data": {
"pokemons": \[
{
"name": "pikachu",
"abilities": \[
{
"name": "Thunder punch",
"damage": 75,
"accuracy": 70,
"mana": 15,
"type": "physical"
},
{
"name": "Thunderbolt",
"damage": 90,
"accuracy": 80,
"mana": 15,
"type": "electric"
}
\]
},
{
"name": "mewtwo",
"abilities": \[
{
"name": "Earthquake",
"damage": 130,
"accuracy": 100,
"mana": 20,
"type": "ground"
},
{
"name": "Brutal swing",
"damage": 180,
"accuracy": 90,
"mana": 25,
"type": "physical"
}
\]
}
\]
}
}
这就是使用 GraphQL 请求和接收数据的方式。好的,目前还不清楚。首先,这个东西在你的架构中处于什么位置?
那个笑着的家伙就是你。要制作我之前展示的包含宝可梦及其技能的payload,你可就麻烦了。你之所以费劲,是因为你使用的REST API并不符合你的需求。你最终只能为每个宝可梦调用一次,然后为每个宝可梦的技能调用一次。
每次应用程序中的逻辑都会向数据库发出请求并发送有效负载。因此,尽管你表面上笑着,但内心却很想自杀。这就是 GraphQL 的用武之地。
有了 GraphQL,问题就不再存在。您只需发起一个 POST 请求,即可通过 GraphQL 请求明确告知所需信息。之后,服务器将管理一切,您即可获得完整的负载。
使用 REST,你可以获得由端点定义的对象。使用 GraphQL,你无需适应后端定义的对象,而是可以动态定义要在客户端接收的对象。这改变了一切。
好吧,这一切都很好,但它具体是如何工作的呢?GraphQL 如何访问数据库并进行查询?要真正理解 GraphQL,你必须亲手实践。
显示代码
我将为你创建一个 JavaScript 实现(NodeJS)。请注意,以下所有内容适用于任何语言。GraphQL逻辑在任何地方都保持不变,因为它首先是一个规范。
要开始使用 GraphQL,请访问官方网站及其全球所有语言的实现列表。为了简化 NodeJS 的使用,我们需要 express-graphql 和 graphql 模块。让我们从安装基础服务器开始。
index.js
const path = require("path");
const express = require("express");
const graphqlHTTP = require("express-graphql");
const graphql = require("graphql");
const { query } = require(path.resolve("schema/query"));
const graphQLSchema = new graphql.GraphQLSchema({ query });
const app = express();
app.use(
"/graphql",
graphqlHTTP({
schema: graphQLSchema,
graphiql: true
})
);
app.listen(8080);
首先,我们调用依赖项。然后在第 6 行查找根查询,并在第 7 行将其传递给主模式。我们启动 Express 服务器,通过 Express 中间件暴露 /graphql 路由,最后监听 8080 端口。现在让我们看看模式内部发生了什么。
模式/query.js
const path = require("path");
const { GraphQLObjectType, GraphQLList } = require("graphql");
const { pokemonsType } = require(path.resolve("schema/types"));
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
type: "Query",
fields: {
pokemons: {
type: new GraphQLList(pokemonsType),
resolve() {
const data = require(path.resolve("data/pokemons.json"));
return data;
}
}
}
});
exports.query = RootQuery;
Schema 是 GraphQL 的核心。它将决定客户端和服务器之间的通信方式。它指定了客户端可以执行的查询、可以检索的数据类型以及这些类型之间的关系。 * 所有内容都定义在此 Schema 中。从根查询开始。
根查询允许 GraphQL 知道可以检索什么类型的数据。在这里,在我的根查询中,我指定了字段 pokemon 第 9 行,它是一个 pokemon 类型的列表(第 10 行)。
然后我们在第 11 行有一个解析器。解析器负责从数据库获取数据。每个字段都会分配一个解析器。我的 pokemon 字段的解析器是一个 pokemon 对象列表。我的解析器通过一个 JSON 文件返回数据,该文件对应于一个 pokemon 数组。
为了简洁起见,我返回的是 JSON 格式的数据。但在实际应用中,你应该调用数据库,进行查询,然后返回数据。现在我们来看看 JSON 格式的数据是什么样的。
模式/types.js
const path = require("path");
const graphql = require("graphql");
const { GraphQLObjectType, GraphQLString, GraphQLList } = graphql;
const abilitiesType = new GraphQLObjectType({
name: "ability",
fields: {
name: {
type: GraphQLString,
resolve: parent => parent.name
},
damage: {
type: GraphQLString,
resolve: parent => parent.damage
},
accuracy: {
type: GraphQLString,
resolve: parent => parent.accuracy
},
mana: {
type: GraphQLString,
resolve: parent => parent.mana
},
type: {
type: GraphQLString,
resolve: parent => parent.type
}
}
});
const pokemonsType = new GraphQLObjectType({
name: "pokemons",
fields: {
name: {
type: GraphQLString,
resolve: parent => parent.name
},
abilities: {
type: new GraphQLList(abilitiesType),
resolve(parent) {
const abilities = require(path.resolve("data/abilities.json"));
return abilities.filter(ability =>
ability.linkedTo.includes(parent.name)
);
}
}
}
});
exports.pokemonsType = pokemonsType;
原理保持不变。我们创建代表数据结构的 GraphQL 对象类型。我们指定字段,并为每个字段分配一个解析器来查找正确的数据。有趣的是,我在这里使用父级的上下文来过滤要为每个宝可梦返回哪些能力(第 44 行)。
如果你想查看这个实现的实际版本,我创建了一个小型公共沙盒,你可以在里面试用。你可以看到所有文件,包括 JSON 文件,并且可以随意更改!
除了 JSON 数据,你也可以通过在 PokéAPI 上执行 fech 来实现同样的功能。这样你也能练习 GraphQL 了。
结语
就这样吧,我的演示就到此为止了。我已经超过了你给我的五分钟时间。关于这项技术还有很多内容可以讲。比如突变、缓存、变量和上下文。我会先讲讲基础知识。如果你想了解更多,并且有空闲时间,我推荐你阅读这篇非常完整的文章!
鏂囩珷鏉ユ簮锛�https://dev.to/jesuisundev/understand-graphql-in-5-minutes-1oa6