使用模式对 GraphQL 响应进行类型保留反序列化

Posted

技术标签:

【中文标题】使用模式对 GraphQL 响应进行类型保留反序列化【英文标题】:type-preserving deserialization of GraphQL response using schema 【发布时间】:2020-10-19 17:13:37 【问题描述】:

我正在尝试为用户定义的 GraphQL 查询的响应编写反序列化代码。该代码可以访问 JSON 序列化形式的查询响应和底层 GraphQL 架构(通过查询端点的 schema.json 或发出自省请求)。

假设以下架构:

scalar Date

type User 
    name: String
    birthday: Date


type Query 
    allUsers: [User]


schema 
    query: Query

还有以下查询:

query 
    allUsers 
        name
        birthday
    

响应可能如下所示(为简洁起见,仅包括完整响应中的data.allUsers-字段):

[
    "name": "John Doe", "birthday": "1983-12-07"
]

我正在尝试以保留类型信息的方式反序列化上述响应,包括任何自定义标量。在上面的示例中,我按照惯例知道 GraphQL 标量 Date 在 Java 中应该反序列化为 LocalDate,但仅从响应中我不知道 birthday 字段代表 GraphQL 标量类型 Date ,因为它在 JSON 中被序列化为常规字符串。

可以做的是尝试为此使用 GraphQL 模式。对于上面的示例,架构可能看起来像这样(为了简洁而缩短):

...
"types": [

  "kind": "OBJECT",
  "name": "User",
  "fields": [
    
      "name": "name",
      "type": 
        "kind": "SCALAR",
        "name": "String"
      
    ,
    
      "name": "birthday"
      "type": 
        "kind": "SCALAR",
        "name": "Date"
      
    
...

根据这些信息,我可以推断出该响应的birthday 字段的类型为Date,并相应地对其进行反序列化。但是,如果查询使用非平凡的 GraphQL 功能,事情就会变得更加复杂。以别名为例:

query 
    allUsers 
        name
        dayOfBirth: birthday
    

此时我已经需要跟踪任何别名(我可以这样做,因为如果我解析查询,该信息是可用的),并回溯那些以找到正确的类型。我担心如果例如,它可能会变得更加复杂。使用片段。

鉴于我使用graphql-java,并且它似乎已经需要处理所有这些情况以进行序列化,我想知道是否有比手动回溯类型更简单的方法来做到这一点来自查询和架构。

【问题讨论】:

【参考方案1】:

如何从模式生成 java 类,然后使用这些类进行反序列化。我以前为此使用过一个插件 - graphql-java-generator

您可能需要稍微增强插件以支持您的自定义标量

它基本上会生成一个 java 客户端,用于以 Java 方式调用 GraphQL 查询。

【讨论】:

建议的解决方案似乎提前生成了一些基于预定义架构的代码,不幸的是这并不真正适合我的需求。我不提前知道确切的模式,只知道一些共同的基本事实,比如一些自定义标量【参考方案2】:

我在反序列化 LocalDate 属性时遇到了同样的问题,即使使用 graphql-java-extended-scalars 库也是如此。

研究我发现这个库很适合查询,但不适用于突变。

我通过自定义 SchemaParserOptions 解决了我的问题,如下所示:

@Bean
public SchemaParserOptions schemaParserOptions() 
    return SchemaParserOptions.newOptions().objectMapperConfigurer((mapper, context) -> 
        mapper.registerModule(new JavaTimeModule());
    ).build();

在对象中我没有使用任何序列化和反序列化注释。

【讨论】:

以上是关于使用模式对 GraphQL 响应进行类型保留反序列化的主要内容,如果未能解决你的问题,请参考以下文章

如何反序列化具有相同名称但不同类型的 API 响应

使用 Json.Net 进行 C# 枚举反序列化:将值转换为类型时出错

如何在我的 graphQL 上下文中反序列化用户

在C#中序列化和反序列化之间保留xml元素的顺序

反序列化 Facebook Workplace SCIM Rest API 响应

单例模式