How to do a toJson encode method on Dart/Flutter? - flutter

I used the fromJson method to recover a Struct with a List from Json decode http request and receiver it on my class, but now i want to do a reverse, i want to pass the data on my class to my toJson method and send him to a Json encode http POST. Please, i new on Dart/Flutter, someone know how to do this?
import 'dart:convert';
List<Itens> userFromJson(String str) =>
List<Itens>.from(jsonDecode(str).map((x) => Itens.fromJson(x)));
class Coletas {
final int codigo;
final String dataIni;
late String? dataFin;
late String? status;
final List<Itens> itemList;
Coletas(
{
required this.dataIni,
this.dataFin,
this.status,
required this.codigo,
required this.itemList
}
);
factory Coletas.fromJson(Map<String, dynamic> json) {
return Coletas(
dataIni: json['dtData'],
codigo: json['iCodigo'],
itemList: List<Itens>.from(json['stItens'].map((x) => Itens.fromJson(x))),
);
}
Map<String, dynamic> toMap() {
return {
'codigo': codigo,
'dataIni': dataIni,
'dataFin': dataFin,
'status': status
};
}
}
class Itens {
final int? id;
final int codigo;
late int quantidade;
late String? status;
final String codigoEAN;
Itens({
this.id,
this.status,
required this.codigo,
required this.codigoEAN,
required this.quantidade,
});
Map<String, dynamic> toJson(){
return {
'icodigo' : codigo,
'sCodigoBarras': codigoEAN,
'iQtd': quantidade
};
}
factory Itens.fromJson(Map<String, dynamic> json) {
return Itens(
codigo: json['iCodigo'],
codigoEAN: json['sCodigoBarras'],
quantidade: json['iQtd'],
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'status': status,
'codigo': codigo,
'codigoEAN': codigoEAN,
'quantidade': quantidade,
};
}
}
I tried to pass ever item on List separeted so, but not happen i expected.
Map<String, dynamic> toJSon(Coletas value) =>
{
'dtData' : dataIni,
'iCodigo': codigo,
'stItens': [],
};

For a better structure - format and use you can look at the flutter serialization documentation : https://docs.flutter.dev/development/data-and-backend/json.
It explains how to create your model and how to generate them to create fromJson and toJson Model based on the defined data. (https://docs.flutter.dev/development/data-and-backend/json#creating-model-classes-the-json_serializable-way)
It will helps you with your parsing - sending - receiving data.

I think you should assign Coletas as
Map<String, dynamic> toJSon(Coletas value) =>
{
'dtData' : value.dataIni,
'iCodigo': value.codigo,
'stItens': value.itemList,
};

Related

Flutter Unhandled Exception: type 'Null' is not a subtype of type 'Response<AuthResponse>' in type cast

I can't seem to figure out the issue in my flutter GetConnect request, I am using the Getx's Getconnect library to send an API request to authenticate users, the requests are authenticated successfully but then the app throws an error when I try to get the user data and token back,
class AuthService {
final IHttpConnect _connect;
const AuthService(IHttpConnect connect) : _connect = connect;
String get _prefix => 'auth';
Future<AuthResponse> authenticateUser(
var body,
) async {
final response = await _connect.post(
'$_prefix/login',
body,
decoder: (value){
print(value);
AuthResponse data = AuthResponse.fromJson(
value as Map<String, dynamic>,
);
return data;
},
);
if (response.success) {
return response.payload!;
} else {
switch (response.statusCode) {
case 404:
throw UserNotFoundException();
default:
throw DefaultException(message: response.payload!.error!);
}
}
}
}
My AuthResponse model looks like this
import 'package:json_annotation/json_annotation.dart';
part 'auth_response.g.dart';
#JsonSerializable()
class AuthResponse {
AuthResponse({
required this.success,
this.data,
this.error,
});
final bool success;
final Data? data;
final String? error;
factory AuthResponse.fromJson(Map<String, dynamic> json) => _$AuthResponseFromJson(json);
Map<String, dynamic> toJson() => _$AuthResponseToJson(this);
}
#JsonSerializable()
class Data {
Data({
required this.token,
required this.user,
});
final String token;
final User user;
factory Data.fromJson(Map<String, dynamic> json) => _$DataFromJson(json);
Map<String, dynamic> toJson() => _$DataToJson(this);
}
#JsonSerializable()
class User {
User({
required this.id,
required this.name,
required this.email,
required this.emailVerifiedAt,
required this.createdAt,
required this.updatedAt,
});
final int id;
final String name;
final String email;
#JsonKey(name: 'email_verified_at')
final DateTime? emailVerifiedAt;
#JsonKey(name: 'created_at')
final DateTime createdAt;
#JsonKey(name: 'updated_at')
final DateTime updatedAt;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
If I print the data I get
{success: true, data: {token: 157|4YXMdrMwDIECxsVSf5hIeON5scCu9lZTQP2B5wXa, user: {id: 1, name: Kenya Friesen, email: mdavis#yahoo.com, email_verified_at: 2022-11-18T00:27:42.000000Z, created_at: 2022-11-18T00:27:42.000000Z, updated_at: 2022-11-18T00:27:42.000000Z}}, error: ddd}
IHttpConnect class
import './response.model.dart';
abstract class IHttpConnect {
Future<Response<T>> get<T>(
String url, {
required T Function(dynamic)? decoder,
});
Future<Response<T>> post<T>(
String url,
Map<String, dynamic> body, {
T Function(dynamic)? decoder,
});
Future<Response<T>> put<T>(
String url,
Map<String, dynamic> body, {
T Function(dynamic)? decoder,
});
Future<Response<T>> patch<T>(
String url,
Map<String, dynamic> body, {
T Function(dynamic)? decoder,
});
Future<Response<T>> delete<T>(
String url, {
required T Function(dynamic)? decoder,
});
}
Response Class
class Response<T> {
final int statusCode;
final T? payload;
bool get success => statusCode <= 200;
const Response({
required this.statusCode,
required this.payload,
});
}
I appreciate any assistance

How to show lists in snapshot.data in flutter

I am new to flutter and I am learning APIs. My API model has a list named result. Can you please tell me how can I display that list and all other variables inside it by using snapshot.data
I am trying to declare
snapshot.data!.result but it is not working. Please give me the solution to this problem
Model code is below
class LeaguesModel {
LeaguesModel({
required this.success,
required this.result,
});
int success;
List<Result> result;
factory LeaguesModel.fromJson(Map<String, dynamic> json) => LeaguesModel(
success: json["success"],
result: List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"success": success,
"result": List<dynamic>.from(result.map((x) => x.toJson())),
};
}
class Result {
Result({
required this.leagueKey,
required this.leagueName,
required this.countryKey,
required this.countryName,
required this.leagueLogo,
required this.countryLogo,
});
String leagueKey;
String leagueName;
String countryKey;
String countryName;
String leagueLogo;
String countryLogo;
factory Result.fromJson(Map<String, dynamic> json) => Result(
leagueKey: json["league_key"],
leagueName: json["league_name"],
countryKey: json["country_key"],
countryName: json["country_name"],
leagueLogo: json["league_logo"],
countryLogo: json["country_logo"],
);
Map<String, dynamic> toJson() => {
"league_key": leagueKey,
"league_name": leagueName,
"country_key": countryKey,
"country_name": countryName,
"league_logo": leagueLogo,
"country_logo": countryLogo,
};
static List<Result> jsontoApiModel(List<dynamic> emote) => emote.map<Result>((item) => Result.fromJson(item)).toList();
}

Flutter abstract class with factory methods

I am new to working with dart/flutter!
Tell me pls how to correctly implement an abstract class in which a factory method is needed
I have a large number of models with the same methods (factory Model.fromJsom, listFromJson)! I want to make an interface for such models, but I don’t understand how to make a factory method and a static in abstract class
Examples
class Post extends Equatable {
Post({
required this.id,
required this.title,
});
final int id;
final String title;
#override
List<Object> get props => [
id,
title,
];
factory Post.fromJson(dynamic json) {
return Post(
id: json['id'] as int,
title: json['name'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
};
}
static List<Post> listFromJson(List<dynamic> json) {
return json.map((value) => Post.fromJson(value)).toList();
}
#override
String toString() {
return '''Post { id: $id, title: $title }''';
}
}
I find it's always a headache to work with JSON array directly. The solution I find is to wrap the List inside another class, in this case ListPost as follows:
class Post {
final int id;
final String title;
Post({required this.id, required this.title});
factory Post.fromJson(Map<String, dynamic> json) => Post(
id: json['id'] as int,
title: json['title'] as String,
);
Map<String, dynamic> toJson() => <String, dynamic>{
'id': id,
'title': title,
};
}
class ListPost {
final List<Post> list;
ListPost({required this.list});
factory ListPost.fromJson(Map<String, dynamic> json) => ListPost(
list: (json['list'] as List<dynamic>)
.map((e) => Post.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> toJson() => <String, dynamic>{
'list': list,
};
}
And the example JSON is like this:
{
"list": [
{"id": 1, "title": "TITLE_1"},
{"id": 2, "title": "TITLE_2"}
]
}
I hope this is workable for you.
You can simply use this website it will convert your json to a dart file and you can easily call the methods .fromJson and .toJson to convert from json to entity and vice versa quicktype website
JSON source
{
"greeting": "Welcome to quicktype!",
"instructions": [
"Type or paste JSON here",
"Or choose a sample above",
"quicktype will generate code in your",
"chosen language to parse the sample data"
]
}
Dart file
import 'dart:convert';
Welcome welcomeFromJson(String str) => Welcome.fromJson(json.decode(str));
String welcomeToJson(Welcome data) => json.encode(data.toJson());
class Welcome {
Welcome({
this.greeting,
this.instructions,
});
String greeting;
List<String> instructions;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
greeting: json["greeting"] == null ? null : json["greeting"],
instructions: json["instructions"] == null ? null : List<String>.from(json["instructions"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"greeting": greeting == null ? null : greeting,
"instructions": instructions == null ? null : List<dynamic>.from(instructions.map((x) => x)),
};
}

How create a interface (class) in Dart for an nested Map

In my Flutter app I receive notifications with a custom payload, like:
{ notification:
{
title: Test,
body: AAAA
},
data:
{
productId: Axe,
page: Products,
click_action: FLUTTER_NOTIFICATION_CLICK
}
}
Everything works well. I also can handle the payload of the notification by access it through:
message['data']['page']
But I rather would like to use an Interface/Class to name the data by key, for example:
message.data.page and message.data.productId
So I tried:
class NotificationMessage {
Map notification;
Map data;
NotificationMessage(this.notification, this.data);
}
...
NotificationMessage _message = message; // Assigning the payload to the final
...
This where I get stuck: here I got the error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'NotificationMessage'.
My class isn't finished yet, but how to continue?
I' aware of json_serializable, but before any tooling, I would like to understand it fully.
First, you need to build the two models for notification and data as follows
class DataMessage {
final String productId;
final String page;
final String click_action;
DataMessage(this.productId, this.page, this.click_action);
factory DataMessage.fromJson(Map<dynamic, dynamic> json) {
return DataMessage(
json['productId'] as String,
json['page'] as String,
json['click_action'] as String,
);
}
}
class NotificationMessage {
final String title;
final String body;
NotificationMessage(this.title, this.body);
factory NotificationMessage.fromJson(Map<dynamic, dynamic> json) {
return NotificationMessage(
json['title'] as String,
json['body'] as String,
);
}
}
The factory method convert map types into model classes.
Then you have to build a model for the response message as follows
class Message {
final NotificationMessage notification;
final DataMessage data;
Message(this.notification, this.data);
factory Message.fromJson(Map<dynamic, dynamic> json) {
final Map<dynamic, dynamic> mapNotification = json['notification'];
final Map<dynamic, dynamic> mapData = json['data'];
final dataModel = DataMessage.fromJson(mapData);
final notificationModel = NotificationMessage.fromJson(mapNotification);
return Message(
notificationModel as NotificationMessage,
dataModel as DataMessage,
);
}
}
Note that the factory method allows you to convert the maps for each model to a class model
So you can define your response as a class
Map<dynamic, dynamic> messageResponse = {
'notification': {'title': 'Test', 'body': 'AAAA'},
'data': {
'productId': 'Axe',
'page': 'Products',
'click_action': 'FLUTTER_NOTIFICATION_CLICK'
}
};
final Message message = Message.fromJson(messageResponse);
print(message.data.productId);
print(message.data.page);
print(message.data.click_action);
print(message.notification.title);
print(message.notification.body);
Hope that can help you
Instance of the json object. this way you can use a map for any instance without modifying the class
{ "notification":
{
"title": "Test",
"body": "AAAA"
},
"data":
{
"productId": "Axe",
"page": "Products",
"click_action": "FLUTTER_NOTIFICATION_CLICK"
}
}
Class looks like;
class NotificationMessage {
NotificationMessage({
this.notification,
this.data,
});
final Notification notification;
final Data data;
factory NotificationMessage.fromJson(Map<String, dynamic> json) => NotificationMessage(
notification: Notification.fromJson(json["notification"]),
data: Data.fromJson(json["data"]),
);
Map<String, dynamic> toJson() => {
"notification": notification.toJson(),
"data": data.toJson(),
};
}
class Data {
Data({
this.productId,
this.page,
this.clickAction,
});
final String productId;
final String page;
final String clickAction;
factory Data.fromJson(Map<String, dynamic> json) => Data(
productId: json["productId"],
page: json["page"],
clickAction: json["click_action"],
);
Map<String, dynamic> toJson() => {
"productId": productId,
"page": page,
"click_action": clickAction,
};
}
class Notification {
Notification({
this.title,
this.body,
});
final String title;
final String body;
factory Notification.fromJson(Map<String, dynamic> json) => Notification(
title: json["title"],
body: json["body"],
);
Map<String, dynamic> toJson() => {
"title": title,
"body": body,
};
}
A function to build as
Future<NotificationMessage> getNotf() {
var parsedJson = json.decode(//your received object);
return NotificationMessage.fromJson(parsedJson);
}
Now you can receive this in a builder such as
_futureNotifications =Future<NotificationMessage>
_futureNotifications = getNotf(); //this is a function and can be used after a gesture or initState
FutureBuilder<NotificationMessage>(
future: _futureNotifications,
builder: (context, snapshot) {
}

flutter dart JsonSerializable with inherited class

I have the following two classes where one is extending from the other like this :
#JsonSerializable(nullable: true)
class Response {
final String responseCode;
final String responseMessage;
final String errorLog;
Response({this.errorLog, this.responseCode, this.responseMessage});
factory Response.fromJson(Map<String, dynamic> json) =>
_$ResponseFromJson(json);
}
.........................................................
#JsonSerializable(nullable: false)
class Verify extends Response {
Data data;
Verify({
this.data,
});
factory Verify.fromJson(Map<String, dynamic> json) => _$VerifyFromJson(json);
Map<String, dynamic> toJson() => _$VerifyToJson(this);
}
and whenever I'm trying to read response class properties from Verify class, it's always null.
so please how to achieve this?
this one I have solved by passing the parameters to super in verify class constructor like this
#JsonSerializable()
class VerifyResponse extends Response {
Data data;
VerifyResponse({
this.data,
String responseCode,
String responseMessage,
}) : super(responseCode: responseCode, responseMessage: responseMessage);
factory VerifyResponse.fromJson(Map<String, dynamic> json) =>
_$VerifyResponseFromJson(json);
Map<String, dynamic> toJson() => _$VerifyResponseToJson(this);
}
and for the response class it remains the same
#JsonSerializable()
class Response {
final String responseCode;
final String responseMessage;
Response({this.responseCode, this.responseMessage});
factory Response.fromJson(Map<String, dynamic> json) =>
_$ResponseFromJson(json);
}
it's a bit annoying but it's what it's.
You should remove 'final' keyword from Response Class
#JsonSerializable(nullable: true)
class Response {
String responseCode;
String responseMessage;
String errorLog;
Response({this.errorLog, this.responseCode, this.responseMessage});
factory Response.fromJson(Map<String, dynamic> json) =>
_$ResponseFromJson(json);
}
It worked by adding super(); explicitly to the child class's constructor.
#JsonSerializable()
class VerifyResponse extends Response {
Data data;
VerifyResponse({
this.data,
String responseCode,
String responseMessage,
//No need to list all parent class properties
}) : super();
factory VerifyResponse.fromJson(Map<String, dynamic> json) =>
_$VerifyResponseFromJson(json);
Map<String, dynamic> toJson() => _$VerifyResponseToJson(this);
}