How to Convert response from api using graphQL to Plain Old Dart Object in flutter? - flutter

I am trying to convert the Json to PODO(Dart Model Class) but getting following error :
[VERBOSE-2:dart_error.cc(16)] Unhandled exception:
FormatException: Unexpected character (at character 2)

Model Class
class FormModel {
final String id;
final String name;
FormModel({this.id, this.name});
factory FormModel.fromJSON(dynamic data) {
return FormModel(id: data["id"], name: data["name"]);
}
}
Creating object from JSON
FormModel form = FormModel.fromJSON(jsonData);

Related

How to send dynamic data in Retrofit API calls in flutter?

I want to add dynamic data in my api calls so using retrofit I am trying this:
#RestApi(baseUrl: Constants.baseUrl)
abstract class AppServiceClient {
factory AppServiceClient(Dio dio, {String baseUrl}) = _AppServiceClient;
#GET("/get-all-country")
Future<AllCountryResponse> getCountries();
#GET("/get-state/{input}")
Future<AllCountryResponse> getStates(#Path("input") instance<StateId>().fetchCountryId);
}
This is my statId class:
class StateId {
StateId();
String countryId = "";
String get fetchCountryId => countryId;
setCountryId(String value) {
countryId = value;
}
}
I want to pass a dynamic data in the get-state api. How can I do this?
I found the solution to this, it was adding field to the parameter
#GET("/get-state/{id}")
Future<AllCountryResponse> getStates(#Path("id") String id);

Encoding to a standard, colon-seperated json in dart/flutter and built_value

In my flutter project, I want to use built_value for json serialization. One of the sample classes is:
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
part 'device.model.g.dart';
abstract class Device implements Resource, Built<Device, DeviceBuilder> {
// Fields
String get name;
String get code;
bool get isActive;
Device._();
factory Device([void Function(DeviceBuilder) updates]) = _$Device;
String toJson() {
return json.encode(serializers.serializeWith(Device.serializer, this));
}
factory Device.fromJson(String jsonString) {
return serializers.deserializeWith(
Device.serializer, json.decode(jsonString))!;
}
static Serializer<Device> get serializer => _$deviceSerializer;
}
I used the build_runner to generate the codes and everything is OK.
Also I have defined the serializers:
part 'serializers.g.dart';
final standardSerializers =
(serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();
#SerializersFor([
Device])
final Serializers serializers = _$serializers;
Now I want to use the toJson() method:
final device = Device((d) => d
..code = "DEV11"
..name = "Some Tools"
..isActive = true);
print(device.toJson());
The output is:
["name","Some Tools","code","DEV11","isActive",true]
which is a List of objects, instead of Map<String, dynamic>. The generated serializer is:
Iterable<Object?> serialize(Serializers serializers, Device object,
{FullType specifiedType = FullType.unspecified})
...
which returns an Iterable of Object?.
How can I make built_value to generate a json with the standard format, i.e:
{"name":"Some Tools","code":"DEV11","isActive":true};
P.S: using the dart encoder,
print(json.encode(device));
results in:
"[\"name\",\"Some Tools\",\"code\",\"DEV11\",\"isActive\",true]"
I made a silly mistake. Should be:
#SerializersFor([
Device,
])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();

How to deserialize Date ISO String to DateTime Object in built_value serialization in dart?

I wanna serialize a json object including an ISOString date to a dart object using built value.
this is a sample json:
{
"title": "test",
"description": "test description",
"date": "2020-06-05T11:42:38.585Z",
"creator": {
"email": "test#test.com"
}
}
this is the model:
abstract class Post implements Built<Post, PostBuilder> {
#nullable
#BuiltValueField(wireName: '_id')
String get id;
String get title;
String get description;
DateTime get date;
#nullable
User get creator;
Post._();
static Serializer<Post> get serializer => _$postSerializer;
factory Post([updates(PostBuilder b)]) = _$Post;
factory Post.fromJson(Map<String, dynamic> map) =>
serializers.deserializeWith(Post.serializer, map);
Map<String, dynamic> toJson() =>
serializers.serializeWith(Post.serializer, this);
}
and this is the error:
Deserializing '[title, test1, description, test1 description, date, 2020-06-05T...' to
'Post' failed due to: Deserializing '2020-06-05T11:42:38.585Z' to 'DateTime' failed due
to: type 'String' is not a subtype of type 'int' in type cast
how do I fix that?
You can import the Iso8601DateTimeSerializer directly from built_value - don't copy the file over to your project.
Your final serializers.dart should look like:
import 'package:built_value/iso_8601_date_time_serializer.dart';
import 'package:built_value/iso_8601_duration_serializer.dart';
import 'package:built_value/serializer.dart';
import 'package:built_value/standard_json_plugin.dart';
part 'serializers.g.dart';
#SerializersFor([
// your built value classes
])
final Serializers serializers = (_$serializers.toBuilder()
..add(Iso8601DateTimeSerializer())
..add(Iso8601DurationSerializer())
..addPlugin(StandardJsonPlugin())
).build();
You need to add a custom DateTime serializer that you can find here: Iso8601DateTimeSerializer
create a new dart file (I named it iso8601_date_time_serializer.dart)
paste the code from 1
add the import to your serializers.dart file (import 'iso8601_date_time_serializer.dart';)
edit your serializers.g.dart file
Serializers _$serializers = (new Serializers().toBuilder()
..add(Iso8601DateTimeSerializer())
..add(Post.serializer) // I assume you have this in yours
..addPlugin(StandardJsonPlugin()))
.build();
Please note that this modification might be deleted if you regenerate the code with build_runner.
In case you want to dig deeper, I got the answer from built_value GitHub issue 454

Flutter: Shuffle BuiltList in Package built_value

I've developed an app that receives questions from an API.
The client uses built_value for checking.
Is there a way to shuffle the objects in
BuiltList<Aufgabe>fragen ?
This is what the client should do.
abstract class Aufgabenbundle
implements Built<Aufgabenbundle, AufgabenbundleBuilder> {
String get nameDerUebung;
String get dateiNameDerPdf;
BuiltList<Aufgabe> get fragen; //These objects should be mixed
Aufgabenbundle._();
factory Aufgabenbundle([updates(AufgabenbundleBuilder b)]) = _$Aufgabenbundle;
String toJson() {
return json
.encode(serializers.serializeWith(Aufgabenbundle.serializer, this));
}
static Aufgabenbundle fromJson(String jsonString) {
return serializers.deserializeWith(
Aufgabenbundle.serializer, json.decode(jsonString));
}
static Serializer<Aufgabenbundle> get serializer => _$aufgabenbundleSerializer;
}
abstract class Aufgabe
implements Built<Aufgabe, AufgabeBuilder> {
String get title;
String get frage;
int get schwierigkeit;
int get antwortZeit;
BuiltList<String> get vorgegebeneAntworten;
int get richtigeAntwort;
#nullable
int get angehakteWert;
Aufgabe._();
factory Aufgabe([updates(AufgabeBuilder b)]) = _$Aufgabe;
static Serializer<Aufgabe> get serializer => _$aufgabeSerializer;
}
The BuiltList is immutable, so you can't shuffle it directly. As with other mutating operations, you need to rebuild it instead.
When you do that, you get a ListBuilder which implements the List interface, including the shuffle method.
So:
var fragen = aufgabenbundle.fragen;
var gemischteFragen = fragen.rebuild((b) => b.shuffle());

Passing constructor as argument in Flutter

I have API communication service in my Flutter app with 10+ different services, and 100+ API calls that heed to parse data. In order to reuse code I've decided to create some common parsing code that is going to parse data from API:
ApiResponse handleObjectResponse({
#required http.Response serverResponse,
#required Function objectConstructor,
}) {
if (serverResponse.statusCode == 200) {
dynamic responseObject = objectConstructor(json.decode(serverResponse.body));
return ApiResponse(responseObject: responseObject);
} else {
ApiError error = responseHasError(serverResponse.body);
return ApiResponse(error: error);
}
}
This way I am able to parse JSON object from API in a reusable way no matter what the Object class is, just by passing constructor function to this method.
When I call this method in any of the Services I've created for fetching data like this:
handleObjectResponse(serverResponse: response, objectConstructor: ChartData.fromJson);
I get error: The getter 'fromJson' isn't defined for the class 'ChartData'.
Try importing the library that defines 'fromJson', correcting the name to the name of an existing getter, or defining a getter or field named 'fromJson'.
Where I think the problem is is in this model class and factory statement, but I don't know how to fix it:
class ChartData {
List<ChartDataPoint> points;
ChartData({
this.points,
});
factory ChartData.fromJson(Map<String, dynamic> json) {
List jsonPoints = json["data"];
return ChartData(
points: List.generate(jsonPoints.length,
(i) => ChartDataPoint.fromJsonArray(jsonPoints[i])));
}
}
You cannot pass constructors as functions. You need to create a function what will call the constructor instead:
(int a) => Foo(a);
Just a 2022 update: since 2.15 it's possible by Class.new, see the complete issue: https://github.com/dart-lang/language/issues/216.
class A {
final String a;
const A(this.a);
#override
String toString() => 'A($a)';
}
class B {
final String b;
const B(this.b);
#override
String toString() => 'B($b)';
}
void main() {
final List<Object Function(String)> constructors = [A.new, B.new];
for (final Object Function(String) constructor in constructors) {
final Object instance = constructor('My Constructor Parameter');
if (instance is A) {
print(instance.toString());
}
}
}
Note that if you're using named params, both class constructors must have the same param name, otherwise the constructor signatures won't match and then it will generate this static error:
The element type X can't be assigned to the list type Y.