在当今互联网时代,越来越多的应用程序采用前后端分离的架构,前端负责渲染页面并与后端进行交互,后端则提供数据接口供前端调用。传统的 RESTful API 虽然使用简单,但是存在一些缺点,比如需要进行多次请求才能获得所需的数据,而且在处理嵌套关系的数据时也不够灵活。而 GraphQL 作为一种新兴的 API 查询语言,正好能够解决这些问题。
什么是 GraphQL?
GraphQL 是一种由 Facebook 开发的 API 查询语言和运行时,其设计理念是将应用程序的数据需求与后端数据提供方面进行解耦。简单来说,GraphQL 可以让前端开发者在查询数据时明确要求所需的数据,由后端提供方返回和客户端需求一致的数据,从而实现前后端数据关系的协调和更好的数据解耦。
GraphQL 的优点
相比于传统的 RESTful API,GraphQL 有以下优点:
- 更好的性能:GraphQL 可以一次性请求所需的所有数据,减少了 HTTP 请求次数,提高了应用程序的性能。
- 更好的灵活性:GraphQL 允许前端开发者在查询数据时明确需要的数据,并返回与需求一致的数据,从而降低了后端开发者的工作量。同时,由于 GraphQL 可以使用任何数据源(例如关系型数据库、非关系型数据,甚至 Web API)作为后台数据提供方,因此可以更好地适应企业应用程序的需求。
- 更好的嵌套查询性能:GraphQL 允许在查询时嵌套请求,从而减少数据处理的往返和数据格式转换的时间,提高了查询速度和灵活性。
如何使用 GraphQL?
1. 安装 GraphQL
使用 GraphQL 需要安装并配置相应的运行环境。在 Node.js 中,可以通过 NPM 包管理器安装 GraphQL。首先需要在命令行中使用以下命令初始化 Node.js 项目:
npm init -y
接着安装 GraphQL 并相应的依赖项:
npm install graphql express express-graphql
其中,express 是 Node.js 的 Web 服务器框架,express-graphql 是配合 express 使用的 GraphQL 中间件。使用 npm ,无需为 GraphQL 应用程序配置自己的数据库,我们将会使用 JSONPlaceholder API 公共测试 API 来取代数据库,以进行演示。
接下来,在 app.js 文件中设置服务器:
-- -------------------- ---- ------- ----- ------- - ------------------- ----- -------------- - --------------------------- ----- - ----------- - - ------------------- -- -- ------- ------ ----- ------ - ------------- ---- ----- - -------- ------ - --- -- -- ------- -------- ----- -------- - - -------- -- -- ------- -------- -- -- ----- ----- --- - ---------- -------- ----------- ---------------- ------- ------- ---------- --------- --------- ----- -- -- -- ----- ---------------- -- -- - -------------------- ------ -- ------------- ---
运行以上代码,然后打开浏览器用地址栏访问 http://localhost:4000/graphql
; 将会看到 GraphQL Playground,如下图所示:
2. 定义 GraphQL Schema
首先需要定义一个 GraphQL Schema,它是一种定义数据类型和查询类型的 GraphQL API 描述语言,类似于数据库中的架构。在定义 Schema 之前,首先需要了解一下 GraphQL 数据类型。
- 标量类型:GraphQL 中的标量类型指非嵌套数据类型,包括 Int、Float、String、Boolean 和 ID。这些类型的值可以直接作为响应数据。
- 列表类型:表示允许返回多个值的数据类型,在 Schema 中是用中括号表示的。
- 对象类型:表示允许返回一组相关数据类型的数据类型,在 Schema 中是用
{}
表示的。
在创建 Schema 时,需要使用 buildSchema 函数。在 Schema 中,可以定义一个或多个类型,每个类型包含一个或多个字段。使用 type 关键字定义类型,字段可以包含标量类型、列表类型和对象类型。
这里,我们来定义一个 Todo 类型,并定义其包含的字段:
-- -------------------- ---- ------- ----- ------ - ------------- ---- ---- - --- ---- ------ ------- ---------- -------- - ---- ----- - --------- ------ - ---
上述代码定义了一个名为 Todo 的类型和一个名为 Query 的类型。在 Todo 类型中,定义了三个字段:id(Int 类型)、title(String 类型)和 completed(Boolean 类型),其中 id 和 title 字段是必需的,由于它们后面带有感叹号,也就是定义了 GraphQL 中的标量类型的非空类型。在 Query 类型中,定义了一个名为 getTodos 的字段,其类型为 [Todo],这表示返回一个 Todo 类型的列表。
3. 定义 GraphQL Resolver
定义 Schema 后,需要定义 Resolver 函数来完成查询逻辑。Resolver 函数是将前端请求转换为 API 响应的中间件。在 Resolver 函数中,可以编写任何代码,用于返回处理后的数据。Resolver 函数与 GraphQL 中定义的每个字段对应,用于对前端请求进行处理,并返回相应的数据。
对于上述定义的 Todo 类型及其所对应的 getTodos 字段,可以这样进行 Resolver 处理:
-- -------------------- ---- ------- ----- -------- - - --------- ----- -- -- - ----- -------- - ----- ------ -------------------------------------------- -- ----- ----- - ----- ---------------- ------ -------------- ---- -- --
在 Resolver 中,使用 ES6 异步函数获取公共测试 API 中的前 10 条待办事项,将其返回给前端。如果发送请求到服务端,将会得到如下数据:
-- -------------------- ---- ------- - ------- - ----------- - - ----- -- -------- --------- --- ------- ------------ ----- -- - ----- -- -------- ----- -- --- ------- -- ------- ----- ------------ ----- -- - ----- -- -------- ------- ------ ------- ------------ ----- -- -- --- - - -
4. 进行查询
对于上述的 getTodos 查询,可以使用 GraphQL 查询语言进行查询。在 Playground 工具的左侧窗格中,可以输入查询和变量。在此之前,我们需要先了解一下 GraphQL 的查询语言。
查询语言
在查询中,需要指定所需的数据。最简单的查询语言是 query { fieldName }
。
例如,我们的 getTodos 查询可以像这样进行查询:
query { getTodos { id title } }
上述查询中,我们要求获取 Todo 类型的所有 id 和 title 字段。发送查询后,服务器响应应该与上面提到的相同。将获取到以下数据:
-- -------------------- ---- ------- - ------- - ----------- - - ----- -- -------- --------- --- ------ -- - ----- -- -------- ----- -- --- ------- -- ------- ---- -- - ----- -- -------- ------- ------ ------ -- -- --- - - -
查询参数
GraphQL 支持在查询中传递参数,可以根据参数来过滤查询结果。
例如,以下是一个名为 getTodo 的查询,并接受一个参数(id),返回指定 ID 的待办事项:
query GetTodoByID($id: Int!) { getTodoByID(id: $id) { id title completed } }
上述查询中,我们使用 query
关键字定义了一个名为 GetTodoByID
的查询。使用 $
单词来定义一个名为 id
的变量并指定类型。例如,在 Playground 窗口中输入变量如下:
{ "id": 2 }
然后运行查询时,我们将传递变量给查询。查询语言将解析由 $
开头的变量名,然后将参数替换为变量所匹配的值。在上述查询中,参数 id
的类型为 Int
,这意味着应该定义一个整数来传递值,这里传递了在查询后面传递的变量值,最后服务端响应结果为:
-- -------------------- ---- ------- - ------- - -------------- - ----- -- -------- ----- -- --- ------- -- ------- ----- ------------ ----- - - -
查询示例
假设一个应用程序需要展示一家餐厅的菜单,以及每个菜品对应的价格、种类和选项等。可能会有这样一个数据模型:
-- -------------------- ---- ------- - ----- ------- ------ - - ----- ------- ------ - - ----- ------- ------ ------ --------- ------- -------- - - ----- ------- ------ ----- - - - - - - -
可以使用 GraphQL 对其进行查询:假设餐厅的名称是“Beauty”,菜单名为“午餐”,我们想要查询出所有菜单项及其相关信息,可以这样写:
-- -------------------- ---- ------- ----- ------------ - ---------------- --------- - ----------- ----- - ----- - ---- ----- -------- ------- - ---- ----- - - - - -
创建/更新/删除操作
GraphQL 也支持进行创建,更新和删除操作,这些操作可以使用 Mutation 操作来完成。Mutation 操作的语法很像查询操作,只是它们不是对现有数据的读取,而是变更现有数据。
例如,在下面的例子中,通过 Mutation 操作可以创建一个新的待办事项:
mutation CreateTodo { createTodo(input: { title: "写一篇 GraphQL 文章" }) { id title completed } }
总结
以上内容仅是 GraphQL 的冰山一角,关于 GraphQL 的复杂功能,比如分页、订阅和错误处理等,需要自行查阅相关文档。但从概念出发,GraphQL 就是一种协商数据协议,允许客户端和服务器之间定义应用程序界面和数据模型的精细映射。它降低了前后端的信息治理成本,并在策略、编码和架构方面带来了新的优势。虽然 GraphQL 并不能使您避免代码编写,但它会使代码更简单。通过与 API 的交互,GraphQL 描述性地重新定义了数据,降低了演进的代价,结果是可以更快地迭代应用程序并提供更好的数据访问控制。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6480292a48841e9894fa742f