flutterrestdartfreezedflutter-freezed

How to fetch two json Value via one field in freezed?


Suppose I have a model class in freezed,

@freezed
abstract class Dto implements _$Dto {
  const factory Dto({
    String? name,
    String? url,
  }) = _Dto;

  factory Dto.fromJson(Map<String, dynamic> json) =>
      _$DtoFromJson(json);
}

Now, the json responses are,

1.

   {
      "name": "superuser root",
      "display_picture_url": "/media_server/user.jpg"
   }
   {
      "name": "superuser root",
      "picture_url": "/media_server/user.jpg"
   }

Without freezed, I write like this,

factory Dto.fromJson(Map<String, dynamic> json) => Dto(
          name: json["name"],
          value: json.containsKey('display_picture_url')
              ? json["display_picture_url"] :
                json["picture_url"] 
        ),
      );

But in freezed, how can I achieve this?

I tried with JsonConverters, But I don't know how to deal with this scenario!


Solution

  • You can do this with readValue parameter of @JsonKey.

    Excerpt from readValue docs:

    At times it's convenient to customize this behavior to support alternative names or to support logic that requires accessing multiple values at once.

    Example:

    Dto/Model setup:
    Object? _urlReader(Map json, String key) {
      if (key == 'picture_url') {
        return json['picture_url'] ?? json['display_picture_url'];
      }
    
      return json[key];
    }
    
    @freezed
    class Dto with _$Dto {
      const factory Dto({
        String? name,
        @JsonKey(name: 'picture_url', readValue: _urlReader) String? url,
      }) = _Dto;
    
      factory Dto.fromJson(Map<String, dynamic> json) => _$DtoFromJson(json);
    }
    
    Test:
    Future<void> testJson() async {
      const json = """
      [
        {
          "name": "Name 01",
          "picture_url": "https://picture.url"
        },
        {
          "name": "Name 02",
          "display_picture_url": "https://display.picture.url"
        }
      ]
      """;
      final decodedJson = jsonDecode(json) as List<dynamic>;
    
      final models = decodedJson.map((e) {
        return Dto.fromJson(e);
      });
    
      debugPrint("$models");
    }
    
    testJson() output:
    (Dto(name: Name 01, url: https://picture.url), Dto(name: Name 02, url: https://display.picture.url))