关于GraphQL中“可嵌入字段”的建议

2020-09-27 04:53:05

我想为GraphQL提出一个新特性的建议,不是附加到官方规范中,而是作为GraphQL服务器可能决定支持的一个可选特性(类似于GraphQL光标连接规范)。

这篇文章是了解GraphQL社区是否支持此功能的基础工作的一部分。如果有,只有那时我才会把它作为新的问题提交给GraphQL规范回收站进行彻底的讨论,并提出成为它的拥护者。

注意:POP的GraphQL已经支持此功能。在本文中,请单击GraphiQL客户端上的“运行”按钮,以执行查询并查看预期的响应。

可嵌入字段是一种语法构造,它允许使用胡子语法{{field}}为同一类型的另一个字段解析参数内的字段。

注意:为了方便使用,可以将字段echo(value:string):string添加到模式中,如本文中的示例所示。

注意:将可嵌入字段与指令@SKIP和@INCLUDE一起使用是一个有趣的用例。但是,条件IF需要的是布尔值,而不是字符串;即使可以在服务器中正确解析查询,客户端中也存在类型不匹配的问题。

此建议可能建议接受嵌入字段本身,而不仅仅是在字符串中,这样就可以将它们强制转换为自己的类型:@Skip(if:{{hasComments}})。下面是关于这一点的更多信息。

此查询以两种不同的方式解析字段标题,具体取决于帖子是否有评论:

为什么我们希望GraphQL查询支持可嵌入字段?以下是我到目前为止已经确定的好处。

在大多数情况下,我们有一个客户端从GraphQL服务器请求数据并将其转换为所需的格式。

例如,客户端的网站可以使用JavaScript处理数据,如将字段Title和Date转换为描述:

但是,在某些情况下,我们可能需要检索我们不能控制的服务的数据,并且该服务不提供处理结果的工具。

例如,时事通讯服务(如Mailchnp)可以接受定义从中检索时事通讯数据的端点。端点返回的任何数据都是最终数据;在注入时事通讯之前,不能对其进行处理。

在这些站点中,查询可以使用可嵌入字段将响应操作为所需的格式。当通过HTTP访问GraphQL时,这可能特别有用。

还可以通过向模式中添加额外的Post.description ptionForNewsetter字段来满足上面的用例。但是这个解决方案使模式变得杂乱无章,而可嵌入字段可以被认为是一个更优雅的解决方案。

可以将可嵌入字段与JavaScript中的箭头函数进行比较,后者在语法上优于该语言中已有的功能。

因此,该特性成为该语言中受欢迎的特性,从而产生更好的开发体验。

目前,@SKIP和@INCLUDE指令的参数";IF";只能是实际的布尔值(TRUE或FALSE)或具有布尔值的变量。此行为相当静态。

通过从对象本身评估某些属性上的条件,可嵌入字段将使此行为更具动态性。

有一个问题需要解决:如果是布尔值,而不是字符串,因此为了避免类型冲突,GraphQL语法可能还需要单独接受嵌入的字段,而不是将其括在字符串引号中:

不需要在引号";";之间换行{{}}将为除字符串之外的所有标量类型解决这个问题,而不仅仅是布尔值(使用droid查看下面的示例,使用可嵌入字段解析ID)。

可嵌入字段允许在GraphQL查询本身中嵌入模板,这将使GraphQL服务更具配置友好性。

例如,结合扁平链语法和嵌套突变(还建议用于规范的另外两个特性),我们可以生成以下查询,该查询向用户发送一封电子邮件,通知他/她的评论已得到回复:

突变{COMMENT(:1){replyToComment(:Data){id@sendEmail(:";{{parentComment.auth.email}}";,:";{{Auth.name}已于{{comment.date(:\";d/m/Y\";))回复了您在{{comment.date(:\";d/m/Y\";{{comment.date(:\";d/m/Y\";{{comment.date(:\";d/m/Y\";)}},{{Author.name}}:<;/p>;<;BLOCKQUOTE>;{{comment.content}}<;/BLOBQUTE>;<;p>;读取:{{comment.url}}<;/p>;";)}}

建议的功能[RFC]在查询之间导出变量尝试@导出字段的值,并将其注入到同一查询中的另一个字段中:

查询A{HERO{id@export(:";droidId";)}}查询B($droidId:string!){droid(:$droidId){name}}。

使用可嵌入字段和扁平链语法,此用例可以满足如下要求:

一旦编写了查询,它应该始终具有相同的含义并返回相同形状的结果。未来的更改不应更改现有模式或查询的含义,也不应以任何其他方式导致现有兼容GraphQL服务变得不符合以前版本的规范。

使用可嵌入字段,上面的查询将生成不同的响应,而且,它甚至可能生成错误消息,就像没有字段Root.world时一样。

另外,考虑字符串引号";";之间没有对{{}}换行的情况,如下查询所示:

目前,此查询会产生语法错误,显示在GraphiQL客户端中,并且可能无法由服务器解析。这种行为将会改变。

由于向后不兼容,建议将可嵌入字段设置为可选加入功能,提示用户在启用前要充分意识到后果。

可嵌入字段会影响GraphQL工作流中的某些组件。这些问题应该如何处理呢?

当字段不存在时,或者如果字段参数接收的值的类型与架构中声明的类型不同,以及其他潜在错误,GraphiQL客户端将显示错误消息。此信息是否也可用于可嵌入字段?

为此,GraphiQL需要解析字段参数输入并识别所有{{fieldName(FieldArgs)}}实例,以便执行验证并显示错误消息。

当嵌入字段不存在时会发生什么情况?例如,如果在下面的查询中,字段{{name}}存在,但{{surname}}不存在:

{";错误";:[";字段';姓氏';不存在,因此';ECHO(值:\";{{姓名}}{{姓氏}}\";)';无法解析";]}。

或者是否应该跳过缺少的字段,但仍然解析该字段,并可能显示警告?例:

{";警告";:[";字段';姓氏";],";数据";:{";用户";:[{";fullName";:";Juan{{surname}}";},{";fullName";:";佩德罗{{SURNAME}}";},{";FULLNAME";:";Manuel{{SURNAME}}";}]}}。

还是应该将失败的领域全部移除?(请注意,每个解析值的末尾仍有一个空格):

{";警告";:[";字段';姓氏';不存在";],";数据";:{";用户";:[{";fullName";:";Juan";},{";fullName";:";Pedro";},{";fullName";:";Manuel";}]}}。

如果我们实际上想打印响应中的字符串";{{field}}";而不进行解析,应该怎么做呢?

它不是GraphQL规范的一部分,而是作为附加的可选规范,并作为GraphQL服务器的选择加入功能提供。

如果仅在字符串中解析,则可嵌入字段不需要更改GraphQL语法。

让一个字段解析另一个字段的值只发生在下一层,而不是像可组合字段那样向下多层。

可嵌入字段由POP支持在GraphQL服务器GraphQL中,以及它对WordPress GraphQL API for WordPress的实现,两者都是一种选择加入的功能。

如果对此功能有足够的支持,我将在GraphQL规范中添加一个RFC问题。欢迎大家在这篇Reddit帖子中提供反馈: