2

I have the following JSON scalar:

"""
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

which I am trying to convert since my query is accepting input: JSON. When testing using graphql playground, query is JSON object thus the following works:

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

This is the custom serializer (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();
  }
}

and the usage:

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>>'.)
  }

So whenever I try to query, it is throwing the linkException stated in the comment on the last line of usage. Any idea what should be the way of serializing it?

Jenny Kim
  • 1,505
  • 2
  • 16
  • 25
  • is the entire reason you're trying to use a serializer to pass your nested parameters to your query? the serializers won't work that way as far as i'm aware – Zennichimaro Dec 12 '21 at 00:50
  • yeah, the whole reason is to make one flexible query that fits all scenario, so is it because nested serializer is not supported? – Jenny Kim Dec 12 '21 at 00:51
  • yes, unfortunately i think your approach won't ever work (that’s not how ferry works or how graphql works either, since graphql is its own language and is not directly JSON). It also defeats the purpose of all the generators and typing in Ferry if you’re trying to make a single flexible/dynamic query. – Zennichimaro Dec 12 '21 at 00:52
  • If you’d like to write a dynamic query and variables like this I’d probably suggest using a different library (e.g. you’d be able to pass an arbitrary map of variables if using graphql_flutter). Even with graphql_flutter or other libraries though you will still be encouraged to write a proper different query each time using specific variables because you shouldn’t be trying to interpolate the variables in the body of the graphql query. – Zennichimaro Dec 12 '21 at 00:52

1 Answers1

2
// 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');

I think you may be misunderstanding the use case. they are there to serialize and deserialize the response if you want to end up with a Dart object that's different from graphql representation. you may want to try rereading this section: https://ferrygraphql.com/docs/custom-scalars/#create-a-custom-serializer

in the example in the docs, the graphql schema returns an int for the timestamp, but we want to actually use a Date object, so that's the purpose of the serializer. it tells ferry to deserialize the int in our responses to a Date so we can use a Date in our dart code. you could still use a json serializer (like in the examples you linked to) but it still would not be in the way you're trying to use it -- it would be if your schema returns a json string and you want to deserialize the json string. for example, in my case, my graphql schema actually does return a "jsonb" type on some objects. in order to handle that, i'm using built_value's default json_object like this:

(
...
          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
Zennichimaro
  • 5,236
  • 6
  • 54
  • 78
  • Dude, I have a similar problem but I'm not a solution, can you view this [question](https://stackoverflow.com/questions/70364842/json-data-types-cannot-be-deserialized-from-a-graphql-query-by-using-ferry-packa)? – Ουιλιαμ Αρκευα Dec 19 '21 at 05:43