GraphQL Server 的 API 设计规范及最佳实践

阅读时长 8 分钟读完

前言

GraphQL 在前端开发中越来越受欢迎,很多公司和团队都开始采用 GraphQL 构建他们的服务端 API。然而,GraphQL 的灵活性与强大性也带来了许多挑战和需要注意的地方。本文将介绍一些 GraphQL 服务器端 API 设计的规范和最佳实践,帮助您设计出更好的 GraphQL API。

设计规范

1. 定义好 Schema

GraphQL 的核心是 Schema。Schema 定义了数据类型、字段以及它们之间的关系。因此,在设计一个 GraphQL API 时,首要任务就是定义好 Schema。

Schema 可以被定义为一个字符串或写成一个类。如果你使用的是 Apollo Server,则可以考虑写成一个类。一个好的 Schema 应该包含以下几个部分:

  • Query:查询数据(必需)
  • Mutation:修改数据(可选)
  • Subscription:实时数据更新(可选)

比如,下面是一个简单的电影 Schema:

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

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

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

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

2. 使用 DataLoader 来优化数据加载

在 GraphQL 中,一个查询中通常会包含多个嵌套的字段,这意味着多次从数据库中读取数据,将会对性能产生较大的影响。

为了解决这个问题,我们可以使用 DataLoader,它可以缓存请求,然后批量处理数据。这样,我们就可以在一个请求中获取所有数据,而不需要多次查询数据库。

比如,假设我们有一个查询返回所有电影及电影演员的姓名:

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

如果没有 DataLoader,GraphQL 服务器会为每个电影和演员姓名分别从数据库开始查询。但是,如果启用 DataLoader,请求将会被缓存并批量处理,从而获得更好的性能。

3. 使用 Context 传递环境信息

在 GraphQL 中,Context 对象在整个查询过程中被传递,并许多库都会支持在 Context 中存储会话、用户授权信息等相关信息。

使用 Context 可以使得在 Resolver 函数之间传递状态信息变得更加容易。

比如,我们可以将用户认证信息,在 Resolver 中通过 Context 传递给查询、修改、删除函数:

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

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

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

4. 参数验证

GraphQL 请求可以包含很多参数,如果没有良好的参数验证机制,则有可能导致不良后果,比如 SQL 注入攻击。

为了避免这种情况,我们需要在 GraphQL 服务器上实施参数验证,可以使用一些现有的库,例如 Joi 或 Yup。

下面是一个使用 Joi 进行参数验证的例子:

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

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

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

最佳实践

1. 分层结构

对于大型的 GraphQL API,我们应该考虑将业务逻辑与数据层分离,这样可以使代码更具可读性和可维护性。

我们可以将 Resolver 的实现放在独立的服务中,并使用 Repository 模式来处理数据操作。这样可以将 Resolver 与数据访问分离,更容易进行单元测试、集成测试等。

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

2. 使用 Dataloader 和 Batch

在处理关系型数据时,批量获取数据和使用 DataLoader 可以极大提高 GraphQL API 的性能。

在 Apollo Server 中使用 DataLoader 很简单。我们只需要定义一个数据加载器,然后在 Resolver 函数中使用。

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

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

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

Batching 也是提高性能的另一种方式。Batching 允许多个请求在一个请求中处理,这样就可以避免重复查询。

3. 利用 Fragment 提高查询可读性

在 GraphQL 中,查询通常包含嵌套的字段,这会导致查询变得冗长且难以理解。为了优化查询的可读性,我们可以使用 Fragment。

Fragment 允许我们定义一个可复用的字段集合,然后将其应用到查询中。

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

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

在这个例子中,actorFields 可以在我们的查询中被多次使用,使我们的查询代码更加简洁和易于理解。

4. 明确错误信息

GraphQL 返回的错误信息可能不够明确或不够详细,这可能会使开发更加困难。

为了提高 GraphQL 的错误信息质量,我们可以捕获并以标准的格式返回错误信息。GraphQL 提供了一个标准的错误结构,其中包含了错误信息、位置和路径。

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

5. 启用缓存

GraphQL 是一种更强大的查询语言,可以提高服务器和客户端的性能。但是,它也会带来一些挑战,例如在重复查询时需要消耗更多的计算资源。

为了避免这个问题,我们可以启用缓存。GraphQL API 的缓存可以提高性能并减少服务器的负载。

我们可以使用一些现有的缓存库,比如 Redis,或者使用一些各种云提供商所提供的缓存服务。

结论

GraphQL 作为一种新兴的技术,已经在很多公司和团队中被广泛使用。在本文中,我们介绍了一些 GraphQL 服务器端 API 设计的规范和最佳实践,并希望它可以帮助您更好地设计出高效和易用的 GraphQL API。

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

纠错
反馈