在 Flutter 的 Ferry Graphql 中序列化标量 JSON 以实现灵活的查询

Posted

技术标签:

【中文标题】在 Flutter 的 Ferry Graphql 中序列化标量 JSON 以实现灵活的查询【英文标题】:Serializing scalar JSON in Flutter's Ferry Graphql for flexible Query 【发布时间】:2022-01-16 01:38:37 【问题描述】:

我有以下 JSON 标量:

"""
The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
"""
scalar JSON

由于我的query 正在接受input: JSON,因此我正在尝试转换它。使用 graphql Playground 进行测试时,查询是 JSON 对象,因此以下工作:

query 
  carts(where: 
    owner:id: "xxx"
    store:name: "yyy"
  ) 
    id
  

# query is the starting from the where: ...
# build.yaml
# build.yaml
gql_build|schema_builder: #same for gql_build|schema_builder + gql_build|var_builder + ferry_generator|req_builder:
  options:
          type_overrides:
            DateTime:
              name: DateTime
            JSON:
              name: BuiltMap<String, dynamic>
              import: 'package:built_collection/built_collection.dart'
gql_build|serializer_builder:
        enabled: true
        options:
          schema: myapp|lib/graphql/schema.graphql
          custom_serializers:
            - import: 'package:myapp/app/utils/builtmapjson_serializer.dart'
              name: BuiltMapJsonSerializer

这是自定义序列化程序(builtmapjson_serializer.dart)

//// lib/app/utils/builtmapjson_serializer.dart
import 'package:built_collection/built_collection.dart';
import "package:gql_code_builder/src/serializers/json_serializer.dart";

class BuiltMapJsonSerializer extends JsonSerializer<BuiltMap<String, dynamic>> 
  @override
  BuiltMap<String, dynamic> fromJson(Map<String, dynamic> json) 
    print('MyJsonSerializer fromJson: $json');
    return BuiltMap.of(json);
  

  @override
  Map<String, dynamic> toJson(BuiltMap<String, dynamic> operation) 
    print('MyJsonSerializer toJson: $operation.toString()');
    return operation.asMap();
  

及用法:

Future testQuery() async 
    Map<String, dynamic> queryMap = 
      "where": 
        "owner": 
          "id": "xxx",
          "store": "name": "yyy"
        
      
    ;
    final req = GFindCartsReq((b) 
      return b..vars.query.addAll(queryMap);
    );
    var resStream = _graphQLService.client.request(req);
    var res = await resStream.first;
    print(
        'linkExceptions: $res.linkException'); // Map: LinkException(Bad state: No serializer for '_InternalLinkedHashMap<String, Map<String, Object>>'.)
  

所以每当我尝试查询时,它都会抛出在最后一行使用的注释中说明的 linkException。知道应该如何序列化它吗?

【问题讨论】:

是您尝试使用序列化程序将嵌套参数传递给查询的全部原因吗?据我所知,序列化程序不会那样工作 是的,整个原因是为了做出一个适合所有场景的灵活查询,是不是因为不支持嵌套序列化程序? 是的,不幸的是,我认为您的方法永远行不通(这不是轮渡的工作方式或 graphql 的工作方式,因为 graphql 是它自己的语言,而不是直接的 JSON)。如果您尝试进行单个灵活/动态查询,它还会破坏所有生成器和输入 Ferry 的目的。 如果你想写一个动态查询和像这样的变量,我可能会建议使用不同的库(例如,如果使用 graphql_flutter,你可以传递任意的变量映射)。即使使用 graphql_flutter 或其他库,但仍会鼓励您每次使用特定变量编写适当的不同查询,因为您不应该尝试在 graphql 查询的主体中插入变量。 【参考方案1】:
// Write query like this
query FindCarts($owner_id: String!, $store_name: String!) 
  carts(where: 
    owner:id: $owner_id
    store:name: $store_name
  ) 
    id
  

// And make request like this:
final req = GFindCartsReq((b) => b..vars.store_name = 'XXX'..vars.owner_id = 'YYY');

我认为您可能误解了用例。如果你想得到一个与 graphql 表示不同的 Dart 对象,它们可以序列化和反序列化响应。您可能想尝试重读本节: https://ferrygraphql.com/docs/custom-scalars/#create-a-custom-serializer

在文档中的示例中,graphql 模式为时间戳返回一个 int,但我们希望实际使用 Date 对象,这就是序列化程序的目的。它告诉 ferry 反序列化我们对 Date 的响应中的 int,以便我们可以在我们的 dart 代码中使用 Date。您仍然可以使用 json 序列化程序(就像您链接到的示例中一样),但它仍然不会以您尝试使用它的方式 - 如果您的架构返回一个 json 字符串并且您想要反序列化json字符串。例如,就我而言,我的 graphql 模式实际上确实在某些对象上返回了“jsonb”类型。为了处理这个问题,我使用了 built_value 的默认 json_object,如下所示:

(
...
          type_overrides:
            jsonb:
              name: JsonObject
              import: "package:built_value/json_object.dart"
          custom_serializers:
            - import: "package:built_value/src/json_object_serializer.dart"
              name: JsonObjectSerializer

【讨论】:

老兄,我也有类似的问题,但我没有解决办法,你能看看这个question吗?

以上是关于在 Flutter 的 Ferry Graphql 中序列化标量 JSON 以实现灵活的查询的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Flutter graphql 订阅与轮渡包一起使用?

Flutter - GraphQL 支持

实现 GraphQL 和 Flutter

如何在 graphql_flutter 中重试对 GraphQLError 的请求

Flutter / GraphQL - 以自定义类型为参数的突变

云原生之Docker实战使用Docker部署Ferry开源工单系统