本文为 GraphQL Schema 设计指南的第二部分,前面的内容请参考GraphQL Schema 设计指南(上)。本文将继续深入讨论 GraphQL Schema 的设计原则和技巧,以及如何优化和维护 Schema。
1. 数据模型的设计
在设计 GraphQL Schema 之前,我们需要先对应用程序的数据模型进行建模。合理的数据模型是一个成功 GraphQL Schema 设计的必要条件。理想情况下,每个数据模型都应该对应一个 GraphQL 类型,这样就可以直接将数据库中的数据映射到 GraphQL 表示形式中。
数据模型的设计需要考虑以下几个因素:
- 数据库的数据类型
- 数据库的关系模型
- 实体属性的关联关系
以下是一个简单的数据库模型示例(使用 MongoDB):
-- -------------------- ---- ------- ----- -------------- - --- -------- ------ ------- -------- ------- ----- ------- ---------- ----- ------- - ----- --------- ---- ------ -- --------- -- ----- --------- ---- --------- --- --- ----- ---------- - --- -------- ------ ------- --------- ------- ----- ------- ---------- ----- --- ----- ------------- - --- -------- -------- ------- ------- - ----- --------- ---- ------ -- ---------- ----- ----- - ----- --------- ---- ---------- -- ---
根据上述数据模型,我们可以设计出以下 GraphQL 类型:
-- -------------------- ---- ------- ---- -------- - ---- --- ------ ------- -------- ------- ----- ------- ---------- ----- ------- ----- --------- ----------- - ---- ---- - ---- --- ------ ------- --------- ------- ----- ------- ---------- ----- - ---- ------- - ---- --- -------- ------- ------- ----- ---------- ----- ----- --------- -
2. 避免过多的嵌套类型
GraphQL 的优势之一是可以轻松地在查询中深度嵌套对象。然而,过多的嵌套可能会导致查询变得复杂和难以维护。
为了避免过多的嵌套,我们可以将某些嵌套类型提取出来,单独定义为 GraphQL 类型。例如,我们可以将 Comment
中的 author
和 post
提取出来,单独定义为 CommentsAuthor
和 CommentsPost
两个类型:
-- -------------------- ---- ------- ---- ------- - ---- --- -------- ------- ------- -------------- ---------- ----- ----- ------------ - ---- ------------- - ---- --- ------ ------- ----- ------- ---------- ----- - ---- ----------- - ---- --- ------ ------- ----- ------- -
这样,我们在查询评论时就可以选择嵌套返回作者和博客文章的全部信息,也可以单独查询作者和博客文章的信息:
-- -------------------- ---- ------- - ------------------- ----- - -------- - --- ------- ------ - --- ----- ---- --------- - --------- ---- - --- ----- ---- - - - - -------- ----- - ---------- --------------------------- - --- ----- ---- --------- - - - ---------- ----- - -------- --------------------------- - --- ----- ---- - -
3. 利用 Union 和 Interface 类型提高 Schema 的灵活性
在 GraphQL Schema 中,我们可以使用 Union 和 Interface 类型实现多态性和灵活的查询。Union 和 Interface 类型可以让我们将不同类型的对象归为一类,提高代码的可读性和可维护性。
3.1 Union 类型
Union 类型可以将多个 GraphQL 类型组合成一个类型。例如,我们可以定义一个 SearchResult
类型,表示搜索返回的多个不同类型的结果:
union SearchResult = BlogPost | User | Comment
当我们需要搜索时,只需要执行一个查询,同时获取多个不同类型的结果:
-- -------------------- ---- ------- ----- - ------------- ---------- - --- -- -------- - --- ----- ------- --------- - --- -- ---- - --- ----- ---- --------- - --- -- ------- - --- ------- ------ - --- - --------- ---- - --- - - - -
3.2 Interface 类型
Interface 类型可以定义一组字段和类型,作为一组类型的公共属性。例如,我们可以将 BlogPost
、 User
和 Comment
定义为 PostEntity
接口类型:
-- -------------------- ---- ------- --------- ---------- - ---- --- -------- ------- ------- ----- ---------- ----- - ---- -------- ---------- ---------- - ---- --- ------ ------- -------- ------- ----- ------- ------- ----- --------- ----------- ---------- ----- - ---- ---- ---------- ---------- - ---- --- ------ ------- --------- ------- ----- ------- ---------- ----- - ---- ------- ---------- ---------- - ---- --- -------- ------- ------- ----- ---------- ----- ----- --------- -
这样,我们就可以使用 PostEntity
接口类型获取所有 PostEntity
的共有属性,同时还可以针对每种类型进行进一步的查询:
-- -------------------- ---- ------- ----- - ----- - --- ------- --------- --- -- -------- - ----- ---- -------- - --- - - - -
4. 定义输入类型
GraphQL Schema 不仅可以定义输出类型,还可以定义输入类型。使用输入类型可以在查询和变更中重复使用参数,提高代码的可读性和可维护性。
例如,我们可以定义一个 CreateUserInput
输入类型,用于在 GraphQL 变更中创建新的用户:
input CreateUserInput { email: String! password: String! name: String! }
然后,在定义 Mutation
类型时,我们可以使用 CreateUserInput
作为参数类型:
type Mutation { createUser(input: CreateUserInput!): User! }
查询或变更时,可以将 CreateUserInput
作为参数传递:
-- -------------------- ---- ------- -------- - ----------------- - ------ ------------------ --------- ----------- ----- ------ ------- -- - --- ----- - -
5. 使用自定义标量类型
除了 GraphQL 的默认标量类型(例如 String
、 Int
、 Float
、 Boolean
和 ID
),我们还可以定义自己的标量类型,以适应特定的应用场景。
例如,我们可以定义一个 Date
标量类型,用于在 GraphQL Schema 中表示日期:
-- -------------------- ---- ------- ------ ---- ---- -------- - ---- --- ------ ------- -------- ------- ----- ------- ---------- ----- ------- ----- --------- ----------- -
在实现 Date
标量类型时,我们需要编写一个解析器函数,将输入转换为 JavaScript Date
类型。以下是一个 Date
标量类型的示例实现:
-- -------------------- ---- ------- ----- - ----------------- - - ------------------- ----- ----------------- - - ----- --- ------------------- ----- ------- ------------ ------- ------ ---- --- ------ ---------------- - -- ------ ---------- ----- - ------ -------------------- - ---- -- ------- ----- --- --------- - ----- ---- - --- ------------ -- --------------------------------- - ------ ------------------- - - ----- --- -------------- ----- --- ---- ------ ------- -- ----------------- - ----- ---- - --- ------------ -- --------------------------------- - ------ ----- - ----- --- -------------- ----- --- ---- ------ ------- -- ----------------- - -- --------- --- ------------ - ----- ---- - --- ---------------- -- --------------------------------- - ------ ----- - - ----- --- -------------- ----- --- ---- ------ ------- -- --- -- -------------- - ------------------
这样,在查询返回时,我们就可以将 createdAt
字段的类型设置为 Date
标量类型:
-- -------------------- ---- ------- ---- -------- - ---- --- ------ ------- -------- ------- ----- ------- ---------- ----- ------- ----- --------- ----------- -
6. 将 Schema 按功能模块拆分
当 Schema 变得复杂时,我们可以将其拆分为多个功能模块,以管理代码并提高可读性和可维护性。例如,我们可以将所有与博客文章相关的查询和变更放在一个独立的子类型中:
-- -------------------- ---- ------- ---- -------- - ---- --- ------ ------- -------- ------- ----- ------- ---------- ----- ------- ----- --------- ----------- - ---- -------- - --------- ---------------- - ---- ----- - --------- ------------- - ---- ---------------- - --------------------- ---------------------- --------- ------------------ ---- ------ ---------------------- --------- ------------------ ----- -------- - ---- ------------- - ---------- ------------ ------------ ----- -------- -
这样,我们就可以根据业务逻辑的不同将 Schema 拆分为多个子类型,并使代码更易于管理和理解。
结论
本文介绍了 GraphQL Schema 设计的一些技巧和最佳实践。通过设计合理的数据模型、避免过多的嵌套类型、利用 Union 和 Interface 类型提高 Schema 的灵活性、定义输入类型、使用自定义标量类型和将 Schema 按功能模块拆分,可以让我们设计出易于维护和扩展的 GraphQL Schema。
最后,我们要认识到,Schema 设计并不是一次性完成的事情。随着应用程序的不断发展和变化,可能需要不断地调整和修改 Schema,以适应新的需求和变化。因此,谨慎地设计和维护 Schema 是实现高效 GraphQL API 的关键。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/670f80e95f5512810264f04d