在 GraphQL 中的突变之前删除只读字段
Remove read-only fields before mutation in GraphQL
我的架构中有一个名为 Article
的类型:
type Article {
id: ID!
updated: DateTime
headline: String
subline: String
}
对于它的更新,updateArticle(id: ID!, article: ArticleInput!)
突变使用了相应的输入类型:
input ArticleInput {
headline: String
subline: String
}
突变本身看起来像这样:
mutation updateArticle($id: ID!, $article: ArticleInput!) {
updateArticle(id: $id, article: $article) {
id
updated
headline
subline
}
}
文章总是作为一个整体保存(而不是一个一个地保存单个字段),所以当我将一篇文章传递给我之前获取的那个突变时,它会抛出像 Unknown field. In field "updated"
、Unknown field. In field "__typename"
和 Unknown field. In field "id"
。这些都有根本原因,即这些字段未在输入类型上定义。
根据 spec,这是正确的行为:
(…) This unordered map should not contain any entries with names not
defined by a field of this input object type, otherwise an error
should be thrown.
现在我的问题是处理这些情况的好方法是什么。我是否应该在我的应用程序代码中列出输入类型允许的所有属性?
如果可能的话,我想避免这种情况,也许有一个实用函数为我切掉它们,它知道输入类型。但是,由于客户端不知道模式,这必须发生在服务器端。因此,不必要的属性将转移到那里,我想这就是为什么不应该首先转移它们的原因。
有没有比维护属性列表更好的方法?
我正在使用 apollo-client
、react-apollo
和 graphql-server-express
。
您可以使用片段进行查询,其中包括数据的所有可变字段。 filter utility 可以使用该片段在突变发生之前删除所有不需要的数据。
要点是:
const ArticleMutableFragment = gql`
fragment ArticleMutable on Article {
headline
subline
publishing {
published
time
}
}
`
const ArticleFragment = gql`
fragment Article on Article {
...ArticleMutable
id
created
updated
}
${ArticleMutableFragment}
`;
const query = gql`
query Article($id: ID!) {
article(id: $id) {
...Article
}
}
${ArticleFragment}
`;
const articleUpdateMutation = gql`
mutation updateArticle($id: ID!, $article: ArticleInput!) {
updateArticle(id: $id, article: $article) {
...Article
}
}
${ArticleFragment}
`;
...
import filterGraphQlFragment from 'graphql-filter-fragment';
...
graphql(articleUpdateMutation, {
props: ({mutate}) => ({
onArticleUpdate: (id, article) =>
// Filter for properties the input type knows about
mutate({variables: {id, article: filterGraphQlFragment(ArticleMutableFragment, article)}})
})
})
...
ArticleMutable
片段现在也可以重复用于创建新文章。
我个人也有同样的想法,并且早些时候采用了@amann 的方法,但一段时间后,在输入类型上使用查询片段的概念缺陷变得明显。您可以选择选择(相应的)对象类型中不存在的输入类型字段 - 甚至有吗?
目前我正在通过 typesafe-joi
模式描述我的输入数据并使用它的 stripUnknown
选项来过滤掉我的表单数据。
无效数据永远不会离开表单,因此可以静态输入有效数据。
在某种意义上,创建 joi 模式与定义 "input fragment" 相同 activity,因此不会发生代码重复,并且您的代码可以是类型安全的。
我的架构中有一个名为 Article
的类型:
type Article {
id: ID!
updated: DateTime
headline: String
subline: String
}
对于它的更新,updateArticle(id: ID!, article: ArticleInput!)
突变使用了相应的输入类型:
input ArticleInput {
headline: String
subline: String
}
突变本身看起来像这样:
mutation updateArticle($id: ID!, $article: ArticleInput!) {
updateArticle(id: $id, article: $article) {
id
updated
headline
subline
}
}
文章总是作为一个整体保存(而不是一个一个地保存单个字段),所以当我将一篇文章传递给我之前获取的那个突变时,它会抛出像 Unknown field. In field "updated"
、Unknown field. In field "__typename"
和 Unknown field. In field "id"
。这些都有根本原因,即这些字段未在输入类型上定义。
根据 spec,这是正确的行为:
(…) This unordered map should not contain any entries with names not defined by a field of this input object type, otherwise an error should be thrown.
现在我的问题是处理这些情况的好方法是什么。我是否应该在我的应用程序代码中列出输入类型允许的所有属性?
如果可能的话,我想避免这种情况,也许有一个实用函数为我切掉它们,它知道输入类型。但是,由于客户端不知道模式,这必须发生在服务器端。因此,不必要的属性将转移到那里,我想这就是为什么不应该首先转移它们的原因。
有没有比维护属性列表更好的方法?
我正在使用 apollo-client
、react-apollo
和 graphql-server-express
。
您可以使用片段进行查询,其中包括数据的所有可变字段。 filter utility 可以使用该片段在突变发生之前删除所有不需要的数据。
要点是:
const ArticleMutableFragment = gql`
fragment ArticleMutable on Article {
headline
subline
publishing {
published
time
}
}
`
const ArticleFragment = gql`
fragment Article on Article {
...ArticleMutable
id
created
updated
}
${ArticleMutableFragment}
`;
const query = gql`
query Article($id: ID!) {
article(id: $id) {
...Article
}
}
${ArticleFragment}
`;
const articleUpdateMutation = gql`
mutation updateArticle($id: ID!, $article: ArticleInput!) {
updateArticle(id: $id, article: $article) {
...Article
}
}
${ArticleFragment}
`;
...
import filterGraphQlFragment from 'graphql-filter-fragment';
...
graphql(articleUpdateMutation, {
props: ({mutate}) => ({
onArticleUpdate: (id, article) =>
// Filter for properties the input type knows about
mutate({variables: {id, article: filterGraphQlFragment(ArticleMutableFragment, article)}})
})
})
...
ArticleMutable
片段现在也可以重复用于创建新文章。
我个人也有同样的想法,并且早些时候采用了@amann 的方法,但一段时间后,在输入类型上使用查询片段的概念缺陷变得明显。您可以选择选择(相应的)对象类型中不存在的输入类型字段 - 甚至有吗?
目前我正在通过 typesafe-joi
模式描述我的输入数据并使用它的 stripUnknown
选项来过滤掉我的表单数据。
无效数据永远不会离开表单,因此可以静态输入有效数据。
在某种意义上,创建 joi 模式与定义 "input fragment" 相同 activity,因此不会发生代码重复,并且您的代码可以是类型安全的。