Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I send request with null field? #473

Closed
bizk-sato opened this issue Jan 20, 2023 · 7 comments
Closed

How can I send request with null field? #473

bizk-sato opened this issue Jan 20, 2023 · 7 comments

Comments

@bizk-sato
Copy link

I want to update a field with null.

So I did something like below.

final req = GUpsertModelReq((b) {
  b.vars.input.field_name = null;

 return b;
}
await client.request(req)

field_name is nullable field in graphql schema.

when I submit the request, it doesn't send the field_name field.
How can I send field with null value?

@knaeckeKami
Copy link
Collaborator

This is currently not supported. It was a limitation of built_value when this library was written originally.

However, built_value supports this now, so we could add an option to ferry_generator to add @BuiltValueSerializer(serializeNulls: true) to serializers of input fields. ( google/built_value.dart#604 )

This would, however, lead to all fields being included and being sent as null even if they were never set, so it's also not a really good solution.

A complete fix would probably require wrapping all nullable values in something like this.

At the moment, I can only offer you a workaround: Write your own class that implements the G...Var() type and implement your own toJson() where you decide what's included or omitted.

@bizk-sato
Copy link
Author

bizk-sato commented Jan 23, 2023

@knaeckeKami
Ok, thanks.

Can you provide sample code or how to implements the G...Var() type and toJson() method?
I mean at the moment toJson() in G..Var() class called, the field_name propeerty doesn't exist in this argument in the method. So I don't know how to decide which value is absent or set to null.

@knaeckeKami
Copy link
Collaborator

You could for example add an additional bool field explictlySetToNull for every variable that gets set to true to decide wether to include it in the toJson() or not.

@zombie6888
Copy link

zombie6888 commented Mar 20, 2023

I was faced with this issue and ended up with custom serializer:

class PassportSerializer extends JsonSerializer<GupdatePassportVars>
    implements StructuredSerializer<GupdatePassportVars> {
  @override
  GupdatePassportVars fromJson(Map<String, dynamic> json) {
    throw UnimplementedError();
  }

  @override
  Map<String, dynamic> toJson(GupdatePassportVars object) {
    final passport = object.passport;   
    final json = object.passport.toJson();
    if (passport.series == null) {
      json['series'] = null;
    }
    if (passport.number == null) {
      json['number'] = null;
    }

    return {
      "passportId": object.passportId?.value,
      "passport": json
    };    
  }
}

Hope it will be fixed soon. Thx for your job!

@knaeckeKami
Copy link
Collaborator

Thanks for sharing a workaround!

I have a draft solution here: gql-dart/gql#381

I am not sure when I can make it production-ready (especially tests, make this an opt-in feature to avoid breaking changes, and code cleanup).

@mattbajorek
Copy link

Extending on what @zombie6888 has posted. Here is a full example:

import 'package:built_value/serializer.dart';
// ignore: implementation_imports
import 'package:gql_code_builder/src/serializers/json_serializer.dart';

import '../../utils/date_utils.dart';
// IMPORT GQueryVars

class QueryVarsSerializer extends JsonSerializer<GQueryVars>
    implements StructuredSerializer<GQueryVars> {
  @override
  GQueryVars fromJson(Map<String, dynamic> json) {
    final builder = GQueryVarsBuilder()
      ..id = json['id']
      ..nullableField = dateTimeFromJsonValue(json['nullableField']);
    return builder.build();
  }

  @override
  Map<String, dynamic> toJson(GQueryVars object) =>
      {'id': object.id, 'nullableField': object.nullableField};

  // Required override method needed to serialize a null value
  // Needs to return a list of all of the key value pairs
  @override
  Iterable<Object?> serialize(
    Serializers serializers,
    GQueryVars object, {
    FullType specifiedType = FullType.unspecified,
  }) =>
      ['id', object.id, 'nullableField', object.nullableField];
}

Then in build.yaml:

targets:
  $default:
    builders:
      ferry_generator|serializer_builder:
        enabled: true
        options:
          schema: app|lib/graphql/schema.graphql
          custom_serializers:
            - import: "IMPORT LOCATION"
              name: QueryVarsSerializer

@knaeckeKami
Copy link
Collaborator

Fixed by

#549
and
gql-dart/gql#381

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants