How to handle different JSON Responses from same source in flutter - json

I have a flutter application retrieving a list/or anything for that matter at some point, and if there's any issue with the request, a different response is received.
For Example:
{
"status" : "success",
"message":
[
{
"updated_on" : "2022-01-09 14:26:07"
}
]
}
For Failure:
{
"status" : "error",
"message" : "Query not found"
}
Using quicktype.io, I have created class as below:
class ResponseList {
ResponseList({
required this.status,
required this.message,
});
String status;
List<dynamic> message;
factory ResponseList.fromJson(Map<String, dynamic> json) => ResponseList(
status: json["status"],
message: List<dynamic>.from(json["message"].map((x) => CLASSNAME.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"status": status,
"message": List<dynamic>.from(message.map((x) => x.toJson())),
};
}
Now, the problem is, on failure, this raises an exception when i try to call ResponseList responseAllFromJson(String str) => ResponseList.fromJson(json.decode(str)); where the exeption says [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'String' is not a subtype of type 'List<dynamic>'.
I want to have a method that checks the status first, whether success or failure and then parses the remaining of the json (in message) or parses the whole json and returns appropriate response (text in case of failure and list of objects in case of success).
Note: I want a reusable code, so that I can pass the response to the method and retrieve it from any point in my application. For example:
static bool responseStatus(dynamic response) {
if (response != null) {
if (responseListFromJson(response).status.trim().toLowerCase() == 'success') {
return true;
}
}
return false;
}
Presently, above raises exception on failure but works smoothly on success.

You can try this way while parsing.
class MainResponse {
String status;
dynamic message;
MainResponse({this.status, this.message});
MainResponse.fromJson(Map<String, dynamic> json) {
status = json['status'];
if(json['message'] is String) {
message = json['message'];
}else {
message = <Message>[];
json['message'].forEach((v) {
message.add(new Message.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
if (this.message != null) {
if(this.message is String) {
data['message'] = this.message;
}else {
data['message'] = this.message.map((v) => v.toJson()).toList();
}
}
return data;
}
}
class Message {
String updatedOn;
Message({this.updatedOn});
Message.fromJson(Map<String, dynamic> json) {
updatedOn = json['updated_on'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['updated_on'] = this.updatedOn;
return data;
}
}
And call this way :
MainResponse mainResponse = MainResponse.fromJson(response);
and this :
if(mainResponse.message is String) {
var data = mainResponse.message as String;
print('parsed String $data');
}else {
var list = mainResponse.message as List<Message>;
print('parsed ${list[0].updatedOn }');
}

Related

How to whole json response store in dart model and access that response via dart model instance in flutter

I'm trying to store my whole JSON response in the dart model class. but the response is not stored in the model.
I got this error in my debug console
this is my JSON response
{
"status": "success",
"message": "retrived successfully",
"data": [
{
"id": 1,
"name": "NEET RAJKOT",
"logo": "https://via.placeholder.com/150/92c952"
},
{
"id": 2,
"name": "MEDICAL",
"logo": "https://via.placeholder.com/150/771796"
},
{
"id": 3,
"name": "NEET",
"logo": "https://via.placeholder.com/150/24f355"
}
]
}
This code is how to I get response and store in model class
response = await http.get(
Uri.parse('api_url'),
headers: {""});
String data = json.decode(response.body);
CoursesModel coursesModel = CoursesModel.fromJson(data);
List<Data> coursesData = coursesModel.data;
This my model class
import 'dart:convert';
import 'package:flutter/foundation.dart';
class CoursesModel {
String status;
String message;
List<Data> data;
CoursesModel({
required this.status,
required this.message,
required this.data,
});
CoursesModel copyWith({
String? status,
String? message,
List<Data>? data,
}) {
return CoursesModel(
status: status ?? this.status,
message: message ?? this.message,
data: data ?? this.data,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'status': status,
'message': message,
'data': data.map((x) => x.toMap()).toList(),
};
}
factory CoursesModel.fromMap(Map<String, dynamic> map) {
return CoursesModel(
status: map['status'] as String,
message: map['message'] as String,
data: List<Data>.from((map['data'] as List<int>).map<Data>((x) => Data.fromMap(x as Map<String,dynamic>),),),
);
}
String toJson() => json.encode(toMap());
factory CoursesModel.fromJson(String source) => CoursesModel.fromMap(json.decode(source) as Map<String, dynamic>);
#override
String toString() => 'CoursesModel(status: $status, message: $message, data: $data)';
#override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CoursesModel &&
other.status == status &&
other.message == message &&
listEquals(other.data, data);
}
#override
int get hashCode => status.hashCode ^ message.hashCode ^ data.hashCode;
}
class Data {
int id;
String name;
String logo;
Data({
required this.id,
required this.name,
required this.logo,
});
Data copyWith({
int? id,
String? name,
String? logo,
}) {
return Data(
id: id ?? this.id,
name: name ?? this.name,
logo: logo ?? this.logo,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'name': name,
'logo': logo,
};
}
factory Data.fromMap(Map<String, dynamic> map) {
return Data(
id: map['id'] as int,
name: map['name'] as String,
logo: map['logo'] as String,
);
}
String toJson() => json.encode(toMap());
factory Data.fromJson(String source) => Data.fromMap(json.decode(source) as Map<String, dynamic>);
#override
String toString() => 'Data(id: $id, name: $name, logo: $logo)';
#override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Data &&
other.id == id &&
other.name == name &&
other.logo == logo;
}
#override
int get hashCode => id.hashCode ^ name.hashCode ^ logo.hashCode;
}
use json_serializable (https://pub.dev/packages/json_serializable) package.
annotate class with #JsonSerilzable (and field with #JsonKey if needed). see the documentation for details.
I'm giving a lot of effort then I got a solution
1st I change fromJson to fromMap and my response takes as a Map
data = json.decode(coursesResponse.body);
coursesModel = CoursesModel.fromMap(data as Map<String,dynamic>);
coursesData = coursesModel.data!;
2nd Change is in the Model class
old-line code in fromMap Method List has List int
factory CoursesModel.fromMap(Map<String, dynamic> map) {
return CoursesModel(
status: map['status'] != null ? map['status'] as String : null,
message: map['message'] != null ? map['message'] as String : null,
data: map['data'] != null ? List<Data>.from((map['data'] as List<int>).map<Data?>((x) => Data.fromMap(x as Map<String,dynamic>),),) : null,
);
}
to change List dynamic
factory CoursesModel.fromMap(Map<String, dynamic> map) {
return CoursesModel(
status: map['status'] != null ? map['status'] as String : null,
message: map['message'] != null ? map['message'] as String : null,
data: map['data'] != null ? List<Data>.from((map['data'] as List<dynamic>).map<Data?>((x) => Data.fromMap(x as Map<String,dynamic>),),) : null,
);
}

Dart/Flutter: Parsing Json object

I am trying to parse some unique JSON data in my Flutter app.
{
"NewDataSet": {
"Route": [
{
"RouteID": "1",
"RouteNum": "20",
"Description": "NORTH DAKOTA "
},
{
"RouteID": "11",
"RouteNum": "25",
"Description": "East SD "
}
]
}
}
I am not sure how to parse this with two objects.
You can use json2dart to convert your json to dart classes even complex and nested json datas will work perfectly.
Here is dart class version of your given json data:
class Autogenerated {
NewDataSet newDataSet;
Autogenerated({this.newDataSet});
Autogenerated.fromJson(Map<String, dynamic> json) {
newDataSet = json['NewDataSet'] != null
? new NewDataSet.fromJson(json['NewDataSet'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.newDataSet != null) {
data['NewDataSet'] = this.newDataSet.toJson();
}
return data;
}
}
class NewDataSet {
List<Route> route;
NewDataSet({this.route});
NewDataSet.fromJson(Map<String, dynamic> json) {
if (json['Route'] != null) {
route = new List<Route>();
json['Route'].forEach((v) {
route.add(new Route.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.route != null) {
data['Route'] = this.route.map((v) => v.toJson()).toList();
}
return data;
}
}
class Route {
String routeID;
String routeNum;
String description;
Route({this.routeID, this.routeNum, this.description});
Route.fromJson(Map<String, dynamic> json) {
routeID = json['RouteID'];
routeNum = json['RouteNum'];
description = json['Description'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['RouteID'] = this.routeID;
data['RouteNum'] = this.routeNum;
data['Description'] = this.description;
return data;
}
}
You can chain the square brackets and simply refer to the respective names, as long as you know the data you're receiving.
import 'dart:convert';
void main() {
decodeJSON();
}
void decodeJSON() async {
String data =
'{"NewDataSet": {"Route": [{"RouteID": "1","RouteNum": "20","Description": "NORTH DAKOTA "},{"RouteID": "11","RouteNum": "25","Description": "East SD "}]}}';
try {
dynamic decoded = await jsonDecode(data);
dynamic newDataSet = await decoded['NewDataSet'];
dynamic routes = await decoded['NewDataSet']['Route'];
print(newDataSet);
print(routes);
} catch (e) {
print(e);
}
}

Hello, I'm trying to figure out how factory constructor working in dart

I've took the code from flutter.dev which use factory for fetching data from the internet.
import 'dart:convert';
Future<Album> fetchAlbum() async {
final response = await http.get('https://jsonplaceholder.typicode.com/albums/1');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
Album({this.userId, this.id, this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
I had tried to repeat it in my code but it didn't work. And I'm confused why it doesn't work because I do the same as in the example.
Future<Album> fetchAlbum() {
Map<String, dynamic> map = {
"photo": "another data",
"id": "dsiid1dsaq",
};
return Album.fromJson(map);
}
class Album {
String photo;
String id;
Album({this.photo, this.id});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
photo: json['photo'],
id: json['id'],
)`
}
}
It tells me that: "A value of type 'Album' can't be returned from function 'fetchAlbum' because it has a return type of 'Future'."
I hope this may help you.
Future<Album> fetchAlbum() async {
Map<String, dynamic> map = {
"photo": "another data",
"id": "dsiid1dsaq",
};
return Album.fromJson(map);
}
or like this
Album fetchAlbum() {
Map<String, dynamic> map = {
"photo": "another data",
"id": "dsiid1dsaq",
};
return Album.fromJson(map);
}
The problem isn't in the factory constructor itself. The problem is you're declaring your function fetchAlbum to be of type Future<Album> when in reality it returns just a Syncronous Album...
The example from the Flutter Documentation has a return type of Future<T> because it uses the async and await keyword when dealing with network requests so it returns a Future.
Change:
Album fetchAlbum() {
Map<String, dynamic> map = {
"photo": "another data",
"id": "dsiid1dsaq",
};
return Album.fromJson(map);
}

convert json to dart

I am a beginner in Flutter, I just want to know how to print productA and 220 in console. The below is json file and also create dart file below.
{
"status": true,
"message": "Data returned successfull",
"data": {
"products": [
{
"productName": "productA",
"productPrice": "220.00",
}
]
}
}
Product.dart
class Product {
bool status;
String message;
Data data;
Product({this.status, this.message, this.data});
Product.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
data = json['data'] != null ? new Data.fromJson(json['data']) : null;
}
}
class Data {
List<Products> products;
Data({this.products});
Data.fromJson(Map<String, dynamic> json) {
if (json['products'] != null) {
products = new List<Products>();
json['products'].forEach((v) {
products.add(new Products.fromJson(v));
});
}
}
}
class Products {
String prodName;
String prodRkPrice;
Products({this.prodName, this.prodRkPrice});
Products.fromJson(Map<String, dynamic> json) {
prodName = json['prodName'];
prodRkPrice = json['prodRkPrice'];
}
}
But still don't know how to print those values.
fetchData() async {
try {
String extractedData =
await http.get('json url').toString();
final parsed = jsonDecode(extractedData).cast(Map<String, dynamic>());
final products = Product.fromJson(parsed);
print(products);
//print(json.decode(response.body));
//print(response[0]);
} catch (error) {
throw (error);
}
}
I have tried using this method but getting errors, don't know how to parse and print those values?
Please help me I am a beginner in Flutter
Change your fetchData to:
Future<void> fetchData() async {
try {
Response response = await http.get('json url'); //getting the response without .toString
Map<String, dynamic> extractedData = jsonDecode(response.body); //converting the response
Product products = Product.fromJson(extractedData);
products.data.products.forEach((product) {
print(product.prodName);
print(product.prodRkPrice);
});
} catch (error) {
throw (error);
}
}
Just remember to match the same attribute names of the api in the Products class:
Products.fromJson(Map<String, dynamic> json) {
prodName = json['productName'];
prodRkPrice = json['productPrice'];
}
This should work:
Map<String, dynamic> message = jsonDecode('{"status": true,"message": "Data returned successfull","data": {"products": [{"productName": "productA","productPrice": "220.00"}]}}');
print(message["data"]["products"][0]["productName"]);
What errors are you getting?
Please try this function
fetchData() async {
try {
var extractedData = await http.get('json url');
Product finalResponse = Product.fromJson(jsonDecode(extractedData.body));
print(finalResponse.products[0].productName);
print(finalResponse);
} catch (error) {
throw (error);
}
}
String urlBase = "https://.....";
Future fetchData async {
var jsonResponse;
var response = await http.get("$urlBase");
if (response != null && response.statusCode == 200) {
jsonResponse = json.decode(response.body);
Object obj= jsonDecode(response.body);
return obj;
} else {
//do something else
}
}
To access the Product A and 220, first you should convert json response into dart object. I Try free online JSON to Dart convertor and here is dart object class
class product_model {
bool status;
String message;
Data data;
product_model({this.status, this.message, this.data});
product_model.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
data = json['data'] != null ? new Data.fromJson(json['data']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['message'] = this.message;
if (this.data != null) {
data['data'] = this.data.toJson();
}
return data;
}
}
class Data {
List<Products> products;
Data({this.products});
Data.fromJson(Map<String, dynamic> json) {
if (json['products'] != null) {
products = new List<Products>();
json['products'].forEach((v) {
products.add(new Products.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.products != null) {
data['products'] = this.products.map((v) => v.toJson()).toList();
}
return data;
}
}
class Products {
String productName;
String productPrice;
Products({this.productName, this.productPrice});
Products.fromJson(Map<String, dynamic> json) {
productName = json['productName'];
productPrice = json['productPrice'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['productName'] = this.productName;
data['productPrice'] = this.productPrice;
return data;
}
}
To access the Product A and value 220, Please use below code.
final Map<String, dynamic> parsed = await wrapper.get_CategoryFull(catid);
final model = product_model.fromJson(parsed);
if (model.data.length > 0) {
if (model.products.length > 0) {
for (int i = 0; i < model.products.length; i++) {
print(" product name " +model.products[i].productName);
print(" product price " +model.products[i].productPrice);
}
}
}

_TypeError (type '(dynamic) => Null' is not a subtype of type '(String, dynamic) => void' of 'f')

I dont know how to fix this error.
Exception has occurred.
_TypeError (type '(dynamic) => Null' is not a subtype of type '(String, dynamic) => void' of 'f')
class _ShowformState extends State<Showform> {
List<MaintenanceInfo> info = [];
#override
void initState() {
super.initState();
fetchData();
}
void fetchData() async {
final data = await http.get('http://192.168.1.35:7000/');
print(data.body);
final jsonData = json.decode(data.body);
setState(() {
jsonData.forEach((v) {
var tmpData = MaintenanceInfo.fromJson(v);
info.add(tmpData);
});
});
}
MaintenanceInfo maintenanceInfoFromJson(String str) =>
MaintenanceInfo.fromJson(json.decode(str));
String maintenanceInfoToJson(MaintenanceInfo data) =>
json.encode(data.toJson());
class MaintenanceInfo {
MaintenanceInfo(
{this.serial,
this.model,
});
String serial;
String model;
factory MaintenanceInfo.fromJson(Map<String, dynamic> json) =>
MaintenanceInfo(
serial: json['serial'],
model: json['model'],);
Map<String, dynamic> toJson() => {
'serial': serial,
'model': model, };}
JSON Format look like this
{ "data": [
{
"serial": "8850124003850",
"model": "280",
},]
}
Ps. I am new on flutter development.
Your model looks problematic. You need to modify it like this:
class MaintenanceInfo {
List<Data> data;
MaintenanceInfo({this.data});
MaintenanceInfo.fromJson(Map<String, dynamic> json) {
if (json['data'] != null) {
data = new List<Data>();
json['data'].forEach((v) {
data.add(new Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.data != null) {
data['data'] = this.data.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
String serial;
String model;
Data({this.serial, this.model});
Data.fromJson(Map<String, dynamic> json) {
serial = json['serial'];
model = json['model'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['serial'] = this.serial;
data['model'] = this.model;
return data;
}
}
You can use this website to convert the JSON to Dart Model.