前言
GraphQL 是一种用于 API 的查询语言,它提供了一种更高效、更强大、更灵活的方式来获取和修改数据。在 GraphQL 中,模式(Schema)是定义 API 的核心部分,它描述了 API 中的所有类型、查询和变更。一个好的模式设计能够提高 API 的可用性和可扩展性,但是在设计模式时,有一些常见的陷阱需要注意。
本文将介绍 GraphQL 模式设计中的常见陷阱,并提供一些实用的技巧来避免它们。
陷阱一:过度使用嵌套类型
在 GraphQL 中,类型可以嵌套在其他类型中。这是一种非常强大的工具,可以使模式更加清晰和可读。然而,在某些情况下,过度使用嵌套类型可能会导致模式过于复杂,难以理解和维护。
例如,考虑以下的查询类型:
-- -------------------- ---- ------- ---- ----- - -------- ----- ---- - ---- ---- - --- --- ----- ------- ------ ------- -------- -------- - ---- ------- - ------- ------- ----- ------- ------ ------- -------- ------- -
在这个模式中,User
类型嵌套了 Address
类型。这个设计看起来很合理,因为每个用户都有一个地址。但是,如果我们想要查询所有用户的地址,我们需要执行以下查询:
-- -------------------- ---- ------- ----- - -------- -- - ------- - ------ ---- ----- ------- - - -------- -- - ------- - ------ ---- ----- ------- - - - --- ---- -
这种查询方式会导致网络请求的数量增加,因为每个用户都需要单独查询。此外,如果我们想要过滤用户的地址,我们需要在每个用户的查询中重复相同的过滤条件。
为了避免这个问题,我们可以将 Address
类型提升为顶级类型,并使用连接(Connection)来关联它和 User
类型:
-- -------------------- ---- ------- ---- ----- - -------- ----- ---- --------- -------- - ---- ---- - --- --- ----- ------- ------ ------- -------- ------------------ - ---- ------- - --- --- ------- ------- ----- ------- ------ ------- -------- ------- - ---- ----------------- - ------ --------------- --------- --------- - ---- ----------- - ----- -------- ------- ------- - ---- -------- - ------------ -------- ---------------- -------- ------------ ------ ---------- ------ -
在这个模式中,我们使用 AddressConnection
类型来表示 User
类型和 Address
类型之间的连接。这个连接包含了一个 edges
数组,其中每个元素都是一个 AddressEdge
类型,它包含了 Address
类型的实例和一个 cursor
字段。我们还定义了一个 PageInfo
类型,它包含了分页信息。
现在,我们可以通过以下方式查询所有用户和他们的地址:
-- -------------------- ---- ------- ----- - -------- - ---- ----- ------- - ----- - ---- - ------ ---- ----- ------- - - - - -
这个查询将返回所有用户和他们的地址,而不需要执行多个网络请求。此外,我们还可以使用连接来过滤用户的地址,而不需要在每个用户的查询中重复相同的过滤条件。
陷阱二:过度使用接口和联合类型
在 GraphQL 中,接口和联合类型是表示多态类型的常用工具。它们允许我们定义一个类型,该类型可以表示多个具体类型的任何一个。这种设计非常灵活,可以帮助我们避免重复的代码和冗余的查询。
然而,在某些情况下,过度使用接口和联合类型可能会导致模式过于复杂,难以理解和维护。
例如,考虑以下的模式:
-- -------------------- ---- ------- --------- ---- - --- --- - ---- ---- ---------- ---- - --- --- ----- ------- ------ ------- - ---- ---- ---------- ---- - --- --- ------ ------- ----- ------- - ---- ----- - -------- ----- ---- -
在这个模式中,我们定义了一个 Node
接口,它包含一个 id
字段。然后,我们定义了两个具体类型 User
和 Post
,它们都实现了 Node
接口。最后,我们定义了一个 Query
类型,它包含了一个 node
查询,该查询可以根据 id
获取任何 Node
类型的实例。
这个模式看起来很好,因为它允许我们通过一个查询来获取任何 Node
类型的实例。但是,如果我们想要查询所有用户和帖子的标题,我们需要执行以下查询:
-- -------------------- ---- ------- ----- - -------- -- - ---------- --- -- ---- - ---- - --- -- ---- - ----- - - -------- -- - ---------- --- -- ---- - ---- - --- -- ---- - ----- - - - --- ---- -
这种查询方式会导致网络请求的数量增加,因为每个节点都需要单独查询。此外,如果我们想要过滤用户或帖子的标题,我们需要在每个节点的查询中重复相同的过滤条件。
为了避免这个问题,我们可以将 User
和 Post
类型提升为顶级类型,并使用连接(Connection)来关联它们:
-- -------------------- ---- ------- ---- ----- - --------- -------- --------- -------- - ---- ---- - --- --- ----- ------- ------ ------- ------ --------------- - ---- ---- - --- --- ------ ------- ----- ------- ------- ----- - ---- -------------- - ------ ------------ --------- --------- - ---- -------- - ----- ----- ------- ------- - ---- -------- - ------------ -------- ---------------- -------- ------------ ------ ---------- ------ -
在这个模式中,我们使用 PostConnection
类型来表示 User
类型和 Post
类型之间的连接。这个连接包含了一个 edges
数组,其中每个元素都是一个 PostEdge
类型,它包含了 Post
类型的实例和一个 cursor
字段。我们还定义了一个 PageInfo
类型,它包含了分页信息。
现在,我们可以通过以下方式查询所有用户和帖子的标题:
-- -------------------- ---- ------- ----- - -------- - ---- ----- ----- - ----- - ---- - ----- - - - - -------- - ----- ------ - ---- ----- - - -
这个查询将返回所有用户和他们的帖子,以及所有帖子和它们的作者,而不需要执行多个网络请求。此外,我们还可以使用连接来过滤用户或帖子的标题,而不需要在每个节点的查询中重复相同的过滤条件。
结论
在 GraphQL 模式设计中,过度使用嵌套类型、接口和联合类型可能会导致模式过于复杂,难以理解和维护。为了避免这个问题,我们可以使用连接来关联顶级类型,并避免过度使用接口和联合类型。
当然,这只是一些常见陷阱的解决方案之一,实际上还有很多其他的技巧和最佳实践,可以帮助我们设计出更好的 GraphQL 模式。如果你想深入了解 GraphQL 模式设计,建议阅读 GraphQL 官方文档 和 GraphQL 官方规范。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/673cee8eface55d72056317e