10月8日至10日,与我们在纽约市相聚,学习关于 GraphQL Federation 和 API 平台工程的最新技巧、趋势和新闻。加入我们参加2024年纽约市 GraphQL Summit
文档
免费开始

使用关注点分离进行命名空间划分

将根级操作字段组织到命名空间中

模式设计

大部分 API将其功能作为字段提供,形成一个扁平结构。例如,GitHub GraphQL API大约有200个这样的根级字段!即使有像Apollo Explorer这样的工具,理解和导航较大的“扁平”图也可以是困难的。查询突变类型,结果是一个扁平的结构。例如,GitHub GraphQL API有大约200个这样的根级字段!即使有了像Apollo Explorer这样的工具,导航和理解较大的“扁平”图表也可能很困难。

注意

务必阅读下面的注意事项部分。虽然命名空间模式在查询方面效果良好,但可能会有副作用,这可能不符合GraphQL规范。

为了提高我们的图逻辑组织能力,我们可以为根级操作字段定义命名空间。这些是,它们进一步定义字段,所有这些都与特定的关注点相关。

例如,我们可以在UsersMutations命名空间对象中定义与User对象相关的所有突变字段

type UsersMutations {
create(profile: UserProfileInput!): User!
block(id: ID!): User!
}

然后,我们可以在Comment突变中定义类似的命名空间:

type CommentsMutations {
create(comment: CommentInput!): Comment!
delete(id: ID!): Comment!
}

现在,我们的UserComment类型都有与它们相关联的create突变字段,这是有效的,因为每个都在单独的命名空间类型内部定义。

最后,我们可以将命名空间类型添加到Mutation类型的根级别字段的返回值中:

type Mutation {
users: UsersMutations!
comments: CommentsMutations!
}

我们可以使用相同的模式来处理涉及UserComment类型的查询:

type UsersQueries {
all: [User!]!
}
type CommentsQueries {
byUser(user: ID!): [Comment!]!
}
# Add a single root-level namespace-type which wraps other queries
type Query {
users: UsersQueries!
comments: CommentsQueries!
}

现在,所有与相关的客户端

mutation CreateNewUser($userProfile: UserProfileInput!) {
users {
create(profile: $userProfile) {
id
firstName
lastName
}
}
}
query FetchAllUsers {
users {
all {
id
firstName
lastName
}
}
}

注意

你不需要在UsersQueries类型的字段名中重复user文本,因为我们已经知道所有这些字段都适用于User对象。

序列突变命名空间

与其他所有 GraphQL 操作的 字段 不同,Mutation 类型的根级别字段必须进行串行解析而不是并行解析。这可以帮助防止两个 突变 字段同时与同一数据进行交互,从而可能导致竞态条件。

mutation DoTwoThings {
one {
success
}
# The `two` field is not resolved until after `one` is resolved.
# It is not resolved at all if resolving `one` results in an error.
two {
success
}
}

使用命名空间后,您实际修改数据的 突变 字段 已不再是根级别字段(而是您的命名空间对象)。因此,突变字段将并行解析。在许多系统中,这不会引起问题(例如,您可能在突变 中使用其他机制以确保事务一致性,如语言串联器)。

mutation DoTwoNestedThings(
$createInput: CreateReviewInput!
$deleteInput: DeleteReviewInput!
) {
reviews {
create(input: $createInput) {
success
}
# Is resolved in parallel with `create`
delete(input: $deleteInput) {
success
}
}
}

如果要在特定操作中保证串行执行,可以使用客户端 创建两个可以串行解析的根 字段:

mutation DoTwoNestedThingsInSerial(
$createInput: CreateReviewInput!
$deleteInput: DeleteReviewInput!
) {
a: reviews {
create(input: $createInput) {
success
}
}
# Is resolved serially after `a` is resolved
b: reviews {
delete(input: $deleteInput) {
success
}
}
}

注意事项

如 GraphQL 技术指导委员会的成员指出,尽管上述方法在 上执行,但它不满足 GraphQL 规范中对以下要求的规定:

除了顶级突变字段外,字段的解析必须始终是无副作用的且幂等的。

因此,建议将任何 GraphQL 突变定义在根级别,以确保它们串行执行,并符合规范的要求。

目前,GraphQL 规范提供的唯一解决方案是将相关的 突变 分组 是使用字段命名约定和仔细排序这些字段 - 目前没有符合规范的方法来处理在根突变类型上有大量字段的情况。然而,有一些有趣的建议来解决这个问题的方案,我们鼓励社区成员审阅并反馈,特别是关于 GraphQL 命名空间提案串行字段提案

下一步
首页
评分文章评分在GitHub上编辑编辑论坛Discord

©2024Apollo Graph Inc.,商号 Apollo GraphQL。

隐私政策

公司