实战经验:使用 GraphQL 构建现代应用程序

阅读时长 11 分钟读完

在当今互联网时代,越来越多的应用程序采用前后端分离的架构,前端负责渲染页面并与后端进行交互,后端则提供数据接口供前端调用。传统的 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 项目:

接着安装 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 查询可以像这样进行查询:

上述查询中,我们要求获取 Todo 类型的所有 id 和 title 字段。发送查询后,服务器响应应该与上面提到的相同。将获取到以下数据:

-- -------------------- ---- -------
-
  ------- -
    ----------- -
      -
        ----- --
        -------- --------- --- ------
      --
      -
        ----- --
        -------- ----- -- --- ------- -- ------- ----
      --
      -
        ----- --
        -------- ------- ------ ------
      --
      -- ---
    -
  -
-

查询参数

GraphQL 支持在查询中传递参数,可以根据参数来过滤查询结果。

例如,以下是一个名为 getTodo 的查询,并接受一个参数(id),返回指定 ID 的待办事项:

上述查询中,我们使用 query 关键字定义了一个名为 GetTodoByID 的查询。使用 $ 单词来定义一个名为 id 的变量并指定类型。例如,在 Playground 窗口中输入变量如下:

然后运行查询时,我们将传递变量给查询。查询语言将解析由 $ 开头的变量名,然后将参数替换为变量所匹配的值。在上述查询中,参数 id 的类型为 Int,这意味着应该定义一个整数来传递值,这里传递了在查询后面传递的变量值,最后服务端响应结果为:

-- -------------------- ---- -------
-
  ------- -
    -------------- -
      ----- --
      -------- ----- -- --- ------- -- ------- -----
      ------------ -----
    -
  -
-

查询示例

假设一个应用程序需要展示一家餐厅的菜单,以及每个菜品对应的价格、种类和选项等。可能会有这样一个数据模型:

-- -------------------- ---- -------
-
  ----- -------
  ------ -
    -
      ----- -------
      ------ -
        -
          ----- -------
          ------ ------
          --------- -------
          -------- -
            -
              ----- -------
              ------ -----
            -
          -
        -
      -
    -
  -
-

可以使用 GraphQL 对其进行查询:假设餐厅的名称是“Beauty”,菜单名为“午餐”,我们想要查询出所有菜单项及其相关信息,可以这样写:

-- -------------------- ---- -------
----- ------------ -
  ---------------- --------- -
    ----------- ----- -
      ----- -
        ----
        -----
        --------
        ------- -
          ----
          -----
        -
      -
    -
  -
-

创建/更新/删除操作

GraphQL 也支持进行创建,更新和删除操作,这些操作可以使用 Mutation 操作来完成。Mutation 操作的语法很像查询操作,只是它们不是对现有数据的读取,而是变更现有数据。

例如,在下面的例子中,通过 Mutation 操作可以创建一个新的待办事项:

总结

以上内容仅是 GraphQL 的冰山一角,关于 GraphQL 的复杂功能,比如分页、订阅和错误处理等,需要自行查阅相关文档。但从概念出发,GraphQL 就是一种协商数据协议,允许客户端和服务器之间定义应用程序界面和数据模型的精细映射。它降低了前后端的信息治理成本,并在策略、编码和架构方面带来了新的优势。虽然 GraphQL 并不能使您避免代码编写,但它会使代码更简单。通过与 API 的交互,GraphQL 描述性地重新定义了数据,降低了演进的代价,结果是可以更快地迭代应用程序并提供更好的数据访问控制。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6480292a48841e9894fa742f

纠错
反馈