flutterdartbuilt-value

Flutter ferry custom scalar serializer "has non-dynamic type"


I'm having a bit of a problem with a custom serializer in flutter ferry graphql package:

I have used exactly the example from the ferry docs: https://ferrygraphql.com/docs/custom-scalars/#create-a-custom-serializer

But I always get the following message when running the builder_runner:

[SEVERE] built_value_generator:built_value on lib/schema.schema.gql.dart:
Error in BuiltValueGenerator for abstract class GDailyForecastInput implements Built<GDailyForecastInput, dynamic>.
Please make the following changes to use BuiltValue:

1. Make field dateStart have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.
2. Make field dateEnd have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.
[SEVERE] built_value_generator:built_value on lib/schema.schema.gql.dart:
Error in BuiltValueGenerator for abstract class GHourlyForecastInput implements Built<GHourlyForecastInput, dynamic>.
Please make the following changes to use BuiltValue:

1. Make field dateStart have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.
2. Make field dateEnd have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.

dateStart and dateEnd are query input values of type Date This is my type overwrite: type_overrides: Date: name: Date Does anyone one why this error happens? I really can't find out what the problem is

Date is define das a scalar in my schema.graphql file:

"""A date string with format `Y-m-d`, e.g. `2011-05-23`."""
scalar Date

Here is my build.yaml file:

targets:
  $default:
    builders:
      gql_build|schema_builder:
        enabled: true
        options:
          type_overrides:
            Date:
              name: Date
              
      gql_build|ast_builder:
        enabled: true
        options:
          type_overrides:
            Date:
              name: Date

      gql_build|data_builder:
        enabled: true
        options:
          type_overrides:
            Date:
              name: Date
          schema: appdemo|lib/schema.graphql

      gql_build|var_builder:
        enabled: true
        options:
          type_overrides:
            Date:
              name: Date
          schema: appdemo|lib/schema.graphql

      gql_build|serializer_builder:
        enabled: true
        options:
          schema: appdemo|lib/schema.graphql
          custom_serializers:
            - import: './serializers/date_serializer.dart'
              name: DateSerializer

      ferry_generator|req_builder:
        enabled: true
        options:
          type_overrides:
            Date:
              name: Date
          schema: appdemo|lib/schema.graphql

I tried debugging already. If I rename my scalar to DateTime everything works fine. (I also have a scalar DateTime in my schema.graphql file.) It's only if I use the name Date that I get this error.

Am I missing something? Do I need to create additionally to the code in the documention a dart Date class and link it or so?


Solution

  • Make sure you also include type_overrides for data_builder, var_builder, and req_builder.

    IMPORTANT We've included only the schema_builder above for brevity, but we will need to include this same type_overrides map for data_builder, var_builder, and req_builder as well. See the complete build.yaml example for more details.

    For example:

    Let's say I have two custom scalar, a primitive and a non-primitive type,

    schema.graphql:

    scalar Date #A datetime string in iso8601.
    scalar Metadata #A map with key string and value any.
    
    type Test {
      id: ID!
      date: Date!
      metadata: Metadata!
    }
    
    type Query {
      getTest(): Test!
    }
    

    date_serializer.dart:

    import 'package:built_value/serializer.dart';
    
    class DateSerializer implements PrimitiveSerializer<DateTime> {
      @override
      DateTime deserialize(
        Serializers serializers,
        Object serialized, {
        FullType specifiedType = FullType.unspecified,
      }) {
        assert(serialized is String,
            "DateSerializer expected 'String' but got ${serialized.runtimeType}");
        return DateTime.parse(serialized is String ? serialized : "");
      }
    
      @override
      Object serialize(
        Serializers serializers,
        DateTime date, {
        FullType specifiedType = FullType.unspecified,
      }) =>
          date.toUtc().toIso8601String();
    
      @override
      Iterable<Type> get types => [DateTime];
    
      @override
      String get wireName => "Date";
    }
    

    metadata_serializer.dart:

    import "package:gql_code_builder/src/serializers/json_serializer.dart";
    
    class MetadataSerializer extends JsonSerializer<Map<String, dynamic>> {
      @override
      Map<String, dynamic> fromJson(Map<String, dynamic> json) => json;
    
      @override
      Map<String, dynamic> toJson(Map<String, dynamic> map) => map;
    }
    
    

    build.yaml:

    targets:
      $default:
        builders:
          gql_build|schema_builder:
            enabled: true
            options:
              type_overrides:
                Metadata:
                  name: Map<String, dynamic>
                Date:
                  name: DateTime
          gql_build|ast_builder:
            enabled: true
    
          gql_build|data_builder:
            enabled: true
            options:
              schema: my_project|lib/schema.graphql
              type_overrides:
                Metadata:
                  name: Map<String, dynamic>
                Date:
                  name: DateTime
          gql_build|var_builder:
            enabled: true
            options:
              schema: my_project|lib/schema.graphql
              type_overrides:
                Metadata:
                  name: Map<String, dynamic>
                Date:
                  name: DateTime
          gql_build|serializer_builder:
            enabled: true
            options:
              schema: my_project|lib/schema.graphql
              custom_serializers:
                - import: 'path/to/metadata_serializer.dart'
                  name: MetadataSerializer
                - import: 'path/to/date_serializer.dart'
                  name: DateSerializer
    
          ferry_generator|req_builder:
            enabled: true
            options:
              schema: my_project|lib/schema.graphql
              type_overrides:
                Metadata:
                  name: Map<String, dynamic>
                Date:
                  name: DateTime
    

    After build you should now have both scalar overridden,

    test.dart:

    client.request(request).first.then((response){
      print(response.data?.test.date.runtimeType);
      print(response.data?.test.metadata.runtimeType);
    })
    
    

    output:

    DateTime
    JsLinkedHashMap<String, dynamic>