- 原文地址:
- 原文作者:
- 项目仓库:
- 译者:
- 译者注:此文为本人第一篇译文,本人作为无 GraphQL 使用背景的初学者,翻译过程亦是学习过程。如果发现译文有错误或者表述不当的地方敬请指正,十分感谢!
API 是互联网行业讨论最多的术语之一,但是很多人并不确切知道 API 到底是什么。基本上,API 代表应用程序编程接口(Application Programming Interface)。顾名思义,它相当于一个“界面”,使人们(开发人员、用户、消费者)能够通过它与数据进行交互。
你可以理解为 API 就像是个酒保,你向酒保要一杯酒,他便把一杯你想要的酒递给你,看起来很简单的事,还有什么问题呢?
构建 API 不是一件困难的事,但学习和理解具体的 API 可能存在一定的困难。多数开发者都会使用你的 API 去开发功能或者只是消费数据,这就要求 API 需要尽可能保持干净、直观。精心设计、直观性强的 API 会非常容易理解和使用。
一直以来,我们都在用 REST 来构建 API,使用这种方式会存在一些问题,例如:
- 多端点
- 开发人员学习理解 API 的成本比较高
- API 的信息过度和信息不足问题
为了解决以上的类似问题,Facebook 创造了 GraphQL。我认为 GraphQL 是当代构建 API 的最佳方式,本文将阐述为什么你应该开始学习 GraphQL,让你了解 GraphQL 的工作原理,以及如何使用 GraphQL 创建设计精良、高效并且功能强大的 API。
你可能已经听说过 GraphQL,因为很多开发者和公司都在使用它。由于 GraphQL 是开源的,所以社区也是很庞大的存在。让我们在实践中学习 GraphQL 的工作原理,领略它的魔力了。
什么是GraphQL?
(译者注:)是 Facebook 开发的一种开源查询语言。它为我们提供了一种更有效的方式来设计、创建和消费我们的 API 。基本上,它是 REST 的替代品。
GraphQL 有很多功能,例如:
- 我们可以编写自己所需的数据,并获得所需的数据。不用再像我们习惯使用的 REST 那样过度获取信息。
- GraphQL 为我们提供了单个端点,不再为同一 API 提供版本2或版本3。
- GraphQL 是强类型的,所以我们可以在执行之前在 GraphQL 类型系统中验证查询。有助于构建更强大的 API。
这是对 GraphQL 的基本介绍,解释了为什么它如此强大以及为什么它如今获得了很多人气。如果想了解更多相关信息,我建议访问 网站去了解。
入门
本文主要目的不是学习如何配置 GraphQL 服务器,所以我们现在不会深入研究。本文的目标是了解 GraphQL 在实践中的工作原理,因此我们将使用一个叫做的零配置GraphQL服务器库。
第一步,我们需要创建一个新文件夹,你可以随意命名。我将它命名为 graphql-server :
mkdir graphql-server复制代码
假定你已经在自己的机器中安装了 npm 或 yarn。如果你不知道它们是什么,npm 和 yarn 是 JavaScript 编程语言的包管理器。对于 Node.js,默认包管理器是 npm。
在创建的文件夹中,输入以下命令:
npm init -y复制代码
如果你使用 yarn :
yarn init 复制代码
npm 会创建一个 package.json
文件,项目安装的所有依赖项和命令都在这个文件中。
接下来,我们来安装本项目要使用的唯一依赖项, 允许你创建零配置的 GraphQL 服务器。由于我们刚刚开始使用 GraphQL,这将帮助我们继续学习更多内容,而不必担心服务器配置。
打开终端进入项目文件夹,键入以下命令:
npm install --save-dev graphpack复制代码
如果你使用 yarn,应该这样:
yarn add --dev graphpack复制代码
安装 Graphpack 之后,转到 package.json
文件中的脚本,并在其中输入以下代码:
"scripts": { "dev": "graphpack", "build": "graphpack build"}复制代码
我们将创建一个名为 src 的文件夹作为整个服务器中唯一的文件夹,然后在 src 文件夹中创建三个文件。
译者注:使用 VSCode 的童鞋可以安装 `GraphQL for VSCode` 插件进行语法高亮
首先,我们创建第一个文件,名叫 schema.graphql
,并在这个文件中输入以下代码:
type Query { hello: String}复制代码
这个 schema.graphql
文件将是我们的整个 GraphQL 架构,稍后我会解释它的作用。
接下来,在 src 文件夹中创建第二个文件 resolvers.js
,并在这个文件中输入以下代码:
import { users } from "./db"const resolvers = { Query: { hello: () => "Hello World!" }}export default resolvers复制代码
这个 resolvers.js
文件将是我们提供将 GraphQL 操作转换为数据的指令的方式。
最后,在src文件夹中创建第三个文件 db.js
,并在这个文件中输入以下代码:
export let users = [ { id: 1, name: "John Doe", email: "john@gmail.com", age: 22 }, { id: 2, name: "Jane Doe", email: "jane@gmail.com", age: 23 }]复制代码
在本教程中,我们没有使用真实数据库。所以这个 db.js
文件将模拟数据库,仅用于学习目的。
现在我们的src文件夹应如下所示:
src |--db.js |--resolvers.js |--schema.graphql复制代码
现在,如果你运行命令 npm run dev
,或者如果你正在使用yarn,则运行 yarn dev
,应该在终端中看到此输出:
现在可以用浏览器打开 localhost:4000
,这意味着我们已准备好开始在 GraphQL 中编写我们的第一个 queries(查询),mutations(突变)和 subscriptions(订阅)。
如果感兴趣可以看看 GraphQL Playground,这是一个功能强大的 GraphQL IDE,可用于更好的开发工作流程。如果你想了解有关 GraphQL Playground 的更多信息,请。
Schema
GraphQL 有自己的语言类型,用于编写 Schema(模式)。这是一种人类可读的模式语法,称为 Schema Definition Language - 模式定义语言(SDL)。无论使用何种技术,SDL都是相同的 - 你可以将其用于你想要的任何语言或框架。这种模式语言非常有用,因为它会让你很容易直观的理解你的 API 将具有哪些类型。
Types
Types(类型)是 GraphQL 最重要的特性之一。Types 是自定义对象,表示 API 的外观。举个例子,如果你正在构建社交媒体应用程序,那么你的 API 可能会有 Posts
、Users
、Likes
、Groups
等 Types。
Types 下有 fields(字段),这些字段返回特定类型的数据。例如,我们要创建一个 User 类型,我们应该有 name
、email
和 age
等字段。字段可以是任何类型,并始终返回一种数据类型,比如 Int、Float、String、Boolean、ID、对象类型列表或自定义对象类型。
现在编写我们的第一个 Type,转到 schema.graphql
文件并用以下内容替换已存在的 Query
类型:
type User { id: ID! name: String! email: String! age: Int}复制代码
每个 User
都将拥有一个 ID
,因此我们为其提供了 ID
类型。User
也会有一个 name
和 email
,所以我们给它们 String
类型,年龄我们给了 Int
类型。很简单吧?
数据类型后面的 !
表示该字段非空(non-nullable),这意味着这些带 !
的字段必须在每个查询中返回一些数据。
在 GraphQL 中有三个主要概念:
- 查询(queries) - 从服务器获取数据
- 突变(mutations) - 修改服务器上的数据并获取更新数据(创建,更新,删除)
- 订阅(subscriptions) - 与服务器保持实时连接
这三个主要概念我会一一解释。
Queries
简单来说,GraphQL 中的查询就是获取数据的方式。GraphQL 中的查询会获得所需的确切数据。不多也不少。这对我们的 API 产生了巨大的积极影响 - 不再像我们使用 REST API 那样过度获取或提取不足信息。
让我们来中创建一个查询类型,首先,在 schema.graphql
中添加一个名为 Query
的新类型:
type Query { users: [User!]!}复制代码
users
查询将返回给我们一个或多个用户的数组。它不会返回 null
,因为我们在后面加了 !
,这意味着它是一个不可为空的查询,应该总是返回一些东西。
既然能返回多个,我们也能返回一个特定用户,在 Query
类型中添加一个新的查询 user
:
type Query { users: [User!]!+ user(id: ID!): User! }复制代码
你会发现查询能够传递参数,查询特定用户的时候把用户的 id
作为参数传入。
那么 GraphQL 如何知道去哪获取到数据返回呢?这就是 resolvers.js
的作用,它会告诉 GraphQL 如何以及在何处获取数据。
打开 resolvers.js
文件,更改一下代码:
import { users } from "./db"const resolvers = { Query: { user: (parent, { id }, context, info) => { return users.find(user => user.id === id) }, users: (parent, args, context, info) => { return users } }}export default resolvers复制代码
解释一下以上代码是如何工作的:
- 每个查询解析器都有四个参数。在
user
函数中,我们将id
作为参数传递,然后返回与传递的id
匹配的特定用户 - 在
users
函数中,我们只是返回已存在的users
数组,它会返回所有的用户
现在,我们将测试我们的查询是否正常工作。浏览器打开 localhost:4000
,在左边输入以下代码然后点运行按钮:
query { users { id name email age }}复制代码
试试返回 id 为 1 的用户:
query { user(id: 1) { id name email age }}复制代码
Mutations
在 GraphQL 中,Mutations 是修改服务器上的数据并获取更新数据的方式。你可以理解为类似 REST 的CUD(CREATE,UPDATE,DELETE)。
我们来创建一个类型突变,我们所有的突变都将在这种类型中结束。在 schema.graphql
文件中编写一个名为 mutation
的新类型:
type Mutation { createUser(id: ID!, name: String!, email: String!, age: Int): User! updateUser(id: ID!, name: String, email: String, age: Int): User! deleteUser(id: ID!): User!}复制代码
上述代码创建了三个 Mutation:
createUser
- 我们传入的参数id
、name
、email
、age
,应该返回一个新的用户updateUser
- 传入id
和新的name
、email
与age
, 应该返回一个更新后的用户deleteUser
- 传入id
,应该返回被删除掉用户的信息
现在,我们去 resolvers.js
文件中,在 Query
对象下方插入一个新的 Mutation
对象。
Mutation: { createUser: (parent, { id, name, email, age }, context, info) => { const newUser = { id, name, email, age } users.push(newUser) return newUser }, updateUser: (parent, { id, name, email, age }, context, info) => { let newUser = users.find(user => user.id === id) newUser.name = name newUser.email = email newUser.age = age return newUser }, deleteUser: (parent, { id }, context, info) => { const userIndex = users.findIndex(user => user.id === id) if (userIndex === -1) throw new Error("User not found.") const deletedUsers = users.splice(userIndex, 1) return deletedUsers[0] } }复制代码
该去 localhost:4000
看看我们写的 Mutations 是否有效了,在页面上输入:
mutation { createUser(id: 3, name: "Robert", email: "robert@gmail.com", age: 21) { id name email age }}复制代码
你也可以尝试一下其他的 Mutation。
Subscriptions
正如我之前所说,Subscriptions (订阅)是你与服务器保持实时连接的方式。这意味着无论何时在服务器中发生事件,并且每当调用该事件时,服务器都会将相应的数据发送到客户端。通过使用订阅,你可以将应用程序更新为不同用户之间的最新更改。
最基本的订阅示例:
subscription { users { id name email age }}复制代码
你会说它与查询非常相似,但它的工作方式和查询不同。当服务器中的某些内容更新时,服务器将运行订阅中指定的 GraphQL 查询,并将更新的结果发送到客户端。我并不打算在这篇文章中使用订阅,但如果你想了解更多关于它们的信息,请。
总结
如你所见,GraphQL 是一项非常强大的新技术。它为我们提供了构建更好和精心设计的 API 的真正能力。这就是为什么我建议你现在开始学习它。
对我来说,它最终将取代 REST。
感谢阅读文章,请在下面发表评论!