在 Flutter 的 Ferry Graphql 中序列化标量 JSON 以实现灵活的查询
Serializing scalar JSON in Flutter's Ferry Graphql for flexible Query
我有以下 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 游乐场进行测试时,查询是 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。知道序列化它的方式应该是什么吗?
// 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 模式 return 是一个用于时间戳的 int,但我们实际上想使用 Date 对象,所以这就是序列化程序的目的。它告诉 ferry 反序列化我们对 Date 的响应中的 int,这样我们就可以在 dart 代码中使用 Date。您仍然可以使用 json 序列化程序(就像在您链接到的示例中一样),但它仍然不会以您尝试使用它的方式出现——如果您的模式 return 是json 字符串并且您想反序列化 json 字符串。例如,在我的例子中,我的 graphql 模式实际上在某些对象上执行 return a "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
我有以下 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 游乐场进行测试时,查询是 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。知道序列化它的方式应该是什么吗?
// 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 模式 return 是一个用于时间戳的 int,但我们实际上想使用 Date 对象,所以这就是序列化程序的目的。它告诉 ferry 反序列化我们对 Date 的响应中的 int,这样我们就可以在 dart 代码中使用 Date。您仍然可以使用 json 序列化程序(就像在您链接到的示例中一样),但它仍然不会以您尝试使用它的方式出现——如果您的模式 return 是json 字符串并且您想反序列化 json 字符串。例如,在我的例子中,我的 graphql 模式实际上在某些对象上执行 return a "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