如何使用GraphQL模式进行类似JSON Schema的数据验证?

22
我们正在研究在我们正在开发的无头CMS的第二版中使用GraphQL。在此CMS的第一版中,我们使用JSON Schema对每个文档进行验证,以针对架构在保存到数据库之前进行验证--例如,如果是博客文章,它将根据“Article”模式进行验证,而如果是综述(“最佳”列表),则将根据“Roundup”模式进行验证。
对于第二版,我们正考虑使用GraphQL进行API。然后我们想到,GraphQL模式基本上与JSON模式并行--它描述了文档结构,字段类型等。
因此,我们可以仅拥有“一个模式真相来源”,即GraphQL模式,并在查询文档和保存新版本时同时用于验证新文档。(请注意,我谈论的是将JSON数据针对GraphQL模式进行验证,而不是针对模式验证GraphQL查询。)
我认为数据将根据模式中的所有字段进行验证,除了弃用的字段,因为您只想针对字段的“最新版本”进行验证。
我们可以采取以下三种方法之一:
1.直接使用GraphQL AST验证文档,即编写自己的数据验证器。
2.使用GraphQL AST生成JSON模式,并使用标准的JSON模式验证器实际验证它。
3.只需接受GraphQL不太适合验证,并分别定义模式-一次在GraphQL中进行查询,一次在JSON模式中进行验证(保持同步很麻烦且容易出错)。
问题:1和2是否是愚蠢的想法?是否存在执行此类数据验证的GraphQL工具?是否有其他方法可以在不定义两次架构的情况下实现这一点?
我们的后端将使用Python编写,但管理UI将是客户端React和JavaScript。这是我们正在谈论的GraphQL模式的缩减版本,支持“Article”和“Roundup”文档类型:
schema {
    query: Query
}

type Query {
    documents: [Document!]!
    document(id: Int): Document!
}

interface Document {
    id: Int!
    title: String!
}

type Article implements Document {
    id: Int!
    title: String!
    featured: Boolean!
    sections: [ArticleSection!]!
}

union ArticleSection = TextSection | PhotoSection | VideoSection

type TextSection {
    content: String!
    heading: String
}

type PhotoSection {
    sourceUrl: String!
    linkUrl: String
    caption: String
    content: String
}

type VideoSection {
    url: String!
}

type Roundup implements Document {
    id: Int!
    title: String!
    isAward: Boolean!
    intro: String
    hotels: [RoundupHotel!]!
}

type RoundupHotel {
    url: String!
    photoUrl: String @deprecated(reason: "photoUrl is deprecated; use photos")
    photos: [RoundupPhoto!]!
    blurb: String!
    title: String
}

type RoundupPhoto {
    url: String!
    caption: String
}

1
你知道 https://github.com/jakubfiala/graphql-json-schema 吗?我用你的 GraphQL 模式试了一下,基本上看起来还不错。https://runkit.com/fdlk/59baf17d01ac700012e110b4 魔鬼可能在细节中隐藏。 - flup
你想使用GraphQL的原因是什么?看起来你会失去很多,因为你有实际的模式验证。 - user9903
你好,刚看到你的问题。在我们公司,我们想使用GraphQL来对JSON产品进行模式/验证。你最终找到了解决方案吗? - zenoh
@ben-hoyt 你最终做了什么? - Adam Arold
@AdamArold 哈哈,你会笑的,但我们使用了WordPress,问题就解决了。 :-) 公司最终走了完全不同的方向,没有建立自己的CMS。 - Ben Hoyt
如果它能正常工作,那就行了,对吧? - Adam Arold
1个回答

2

不确定性水平在不断变化的情况下

GraphQL仍然是一项不断发展的技术(正如规范文档顶部所述),因此可以说没有真正的“正确”答案。

概括

InputObject类型(在接口定义语言术语中为“input”)以及列表(在IDL术语中为“[]”)和各种标量似乎完全涵盖了您可以在JSON中执行的操作。

如果Python实现的GraphQL符合规范,那么将数据提供为GraphQL字面值或(更好地)作为“变量”,应该提供自定义验证所需的所有内容:GraphQL验证将完成正确的操作。

针对您的情况的建议

根据我迄今为止使用GraphQL的经验,我的建议是“随波逐流”。如果您的GraphQL模式符合您的数据架构要求,请使用普通的GraphQL验证。如果您确实进行自己的验证,则应在GraphQL完成其正常数据形状检查后进行。

总结以上观点,并回答您的问题:让GraphQL在其正常运行中完成验证重活有何不妥之处?


谢谢。经过进一步的研究,我认为主要问题在于输入类型不能是联合类型或包含联合类型。我们的模式中肯定包含联合类型,因此我们无法将其用作变异的输入类型(除非使用hack)。另请参见https://github.com/facebook/graphql/issues/114 - Ben Hoyt
我错了吗?你可以针对每个输入类型拥有一个输入查询(无论是“query”还是“mutation”)吗?(你可以从现有的输入联合自动生成这些内容)。或者你是在说请求方不知道它是哪种类型?如果是这样,你可以拥有一个通用的“分发”查询,其输出是一个联合类型。 - Ed.
我不太确定你在建议什么:你的意思是创建 updateArticle()updateRoundup() 变更吗?是的,你可以这么做。内部联合仍然存在问题,例如上面的 ArticleSection -- 你可以通过使用 ArticleSectionInput 类型并为联合中每种类型提供可空字段(如:textSectionphotoSectionvideoSection)来解决这个问题...但它非常混乱。 - Ben Hoyt
我建议使用updateArticleupdateRoundup。您还需要createTextSectioncreatePhotoSection等。由于这是输入,您会知道您正在创建什么,因此不需要多态性。鉴于GraphQL已经规定了输入和输出对象之间的分离,无论您做什么,都会有一定程度的重复。 - Ed.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接