I`m trying to use an http get method in flutter, but my json is returned like this:
{"items":[{"id":1,"nome":"Ricardo","telefone":"(14) 99797-5621"}],"hasMore":false,"limit":25,"offset":0,"count":1,"links":[{"rel":"self","href":"http://172.16.30.120:8080/ords/apiteste/integrafoods/users"},{"rel":"describedby","href":"http://172.16.30.120:8080/ords/apiteste/metadata-catalog/integrafoods/item"},{"rel":"first","href":"http://172.16.30.120:8080/ords/apiteste/integrafoods/users"}]}
And i`m trying to retrieve info this way:
Future<void> _loadUsers() async {
final response = await http.get(
Uri.parse(_url),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
if (response.body == 'null') return;
Map<String, dynamic> data = jsonDecode(response.body);
data.forEach(
(items, userData) {
teste.add(
AppUser(
id: items,
login: userData['login'],
phoneNumber: userData['telefone'],
),
);
},
);
print(_teste.length);
}
But it's not working, it throws error: "[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'".
But if i use code this way, it returns all parameters from the json:
Future<void> _loadUsers() async {
final response = await http.get(
Uri.parse(_url),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
if (response.body == 'null') return;
Map<String, dynamic> data = jsonDecode(response.body);
data.forEach(
(items, userData) {
teste.add(
AppUser(
login: userData['items'].toString(),
),
);
},
);
print(_teste.length);
}
How can i map this "items" json so i get each parameter separetadely?
class AppUser {
// final String CPF;
final String id;
final String? login;
final String? name;
final String? email;
final String? situation;
final String? phoneNumber;
final String? password;
final String? inclusionDt;
final String? inclusionUs;
final String? altDt;
final String? altUs;
final String company;
const AppUser({
// required this.CPF,
required this.id,
this.login,
this.name,
this.email,
this.situation,
this.phoneNumber,
this.password,
this.inclusionDt,
this.inclusionUs,
this.altDt,
this.altUs,
this.company = 'GTFoods',
});
}
You can use this model class
import 'dart:convert';
class MyItem {
final int id;
final String? nome;
final String? telefone;
MyItem({
required this.id,
required this.nome,
required this.telefone,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'id': id});
if (nome != null) {
result.addAll({'nome': nome});
}
if (telefone != null) {
result.addAll({'telefone': telefone});
}
return result;
}
factory MyItem.fromMap(Map<String, dynamic> map) {
return MyItem(
id: int.tryParse(map['id'].toString()) ?? 0,
nome: map['nome'],
telefone: map['telefone'],
);
}
String toJson() => json.encode(toMap());
factory MyItem.fromJson(String source) => MyItem.fromMap(json.decode(source));
}
Try using
final data = jsonDecode(response.body)['items'] as List?;
if (data != null) {
final items = data.map((e) => MyItem.fromJson(e)).toList();
print(data);
}
Related
How to fetch data from the model that look like this http://lovemonster.my.id/hospital to my BLoC builder in form of list? i got an error message when i fetch it Type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>' and this is my provider:
class ApiProvider {
final Dio _dio = Dio();
final String _url = 'http://lovemonster.my.id/hospital';
Future<HospitalListModel> fetchHospitalList() async {
try {
Response response = await _dio.get(_url);
return HospitalListModel.fromJson(response.data);
} catch (error, stacktrace) {
print("Exception occurred: $error stackTrace: $stacktrace");
return Future.error("");
}
}
}
and this is my repository:
class ApiRepository {
final _provider = ApiProvider();
Future<HospitalListModel> fetchHospitalList() {
return _provider.fetchHospitalList();
}
}
class NetworkError extends Error {}
this is the model, in case you want to know how it looks like:
class HospitalListModel {
int? id;
String? title;
String? content;
String? image;
String? phone;
String? coordinates;
String? website;
String? createdAt;
String? updatedAt;
HospitalListModel({
this.id,
this.title,
this.content,
this.image,
this.phone,
this.coordinates,
this.website,
this.createdAt,
this.updatedAt,
});
HospitalListModel.fromJson(Map<String, dynamic> json) {
id = json['id'] as int?;
title = json['title'] as String?;
content = json['content'] as String?;
image = json['image'] as String?;
phone = json['phone'] as String?;
coordinates = json['coordinates'] as String?;
website = json['website'] as String?;
createdAt = json['created_at'] as String?;
updatedAt = json['updated_at'] as String?;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> json = <String, dynamic>{};
json['id'] = id;
json['title'] = title;
json['content'] = content;
json['image'] = image;
json['phone'] = phone;
json['coordinates'] = coordinates;
json['website'] = website;
json['created_at'] = createdAt;
json['updated_at'] = updatedAt;
return json;
}
}
can anyone show me how to fetch the data from my API
// To parse this JSON data, do
//
// final hospitalListModel = hospitalListModelFromJson(jsonString);
import 'dart:convert';
List<HospitalListModel> hospitalListModelFromJson(String str) => List<HospitalListModel>.from(json.decode(str).map((x) => HospitalListModel.fromJson(x)));
String hospitalListModelToJson(List<HospitalListModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class HospitalListModel {
HospitalListModel({
this.id,
this.title,
this.content,
this.image,
this.phone,
this.coordinates,
this.website,
this.createdAt,
this.updatedAt,
});
dynamic id;
dynamic title;
dynamic content;
dynamic image;
dynamic phone;
dynamic coordinates;
dynamic website;
dynamic createdAt;
dynamic updatedAt;
factory HospitalListModel.fromJson(Map<String, dynamic> json) => HospitalListModel(
id: json["id"],
title: json["title"],
content: json["content"],
image: json["image"],
phone: json["phone"],
coordinates: json["coordinates"],
website: json["website"],
createdAt: json["created_at"],
updatedAt: json["updated_at"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"content": content,
"image": image,
"phone": phone,
"coordinates": coordinates,
"website": website,
"created_at": createdAt.toIso8601String(),
"updated_at": updatedAt.toIso8601String(),
};
}
call this from here
final hospitalListModel = hospitalListModelFromJson(jsonString);
Example:
Future<List<HospitalListModel>> fetchHospitalList() async {
try {
Response response = await _dio.get(_url);
return hospitalListModelFromJson(response.body);
} catch (error, stacktrace) {
print("Exception occurred: $error stackTrace: $stacktrace");
return Future.error("");
}
}
I'm new to programming and currently learning JSON. I got this error when using Cubit to access the JSON:
RestaurantFailed(type 'Null' is not a subtype of type 'List<RestaurantModel>')
JSON Sample: https://restaurant-api.dicoding.dev/list
I'm trying to access the API and insert it to RestaurantModel.
this is my code:
restaurant_service.dart
class RestaurantService {
Future<List<RestaurantModel>> fetchAllData() async {
try {
Uri url = Uri.http('restaurant-api.dicoding.dev', '/list');
http.Response response = await http.get(url);
Map<String, dynamic> result = jsonDecode(response.body);
List<RestaurantModel> restaurants = result['restaurants'].forEach((json) {
return RestaurantModel.fromJson(json: json);
});
return restaurants;
} catch (e) {
rethrow;
}
}
}
restaurant_cubit.dart
class RestaurantCubit extends Cubit<RestaurantState> {
RestaurantCubit() : super(RestaurantInitial());
void fetchData() async {
try {
emit(RestaurantLoading());
List<RestaurantModel> restaurants =
await RestaurantService().fetchAllData();
emit(RestaurantSuccess(restaurants));
} catch (e) {
emit(RestaurantFailed(e.toString()));
}
}
}
restaurant_model.dart
class RestaurantModel {
final String id;
final String name;
final String description;
final String pictureId;
final String city;
final double rating;
String? address;
List<String>? categories;
List<String>? menus;
List<CustomerReviewModel>? customerReviews;
RestaurantModel({
required this.id,
required this.name,
required this.description,
required this.pictureId,
required this.city,
this.rating = 0.0,
this.address = '',
this.categories,
this.menus,
this.customerReviews,
});
factory RestaurantModel.fromJson({required Map<String, dynamic> json}) =>
RestaurantModel(
id: json['id'],
name: json['name'],
description: json['description'],
pictureId: json['pictureId'],
city: json['city'],
rating: json['rating'].toDouble(),
address: json['address'] ?? '',
categories: json['categories'] ?? [],
menus: json['menus'] ?? [],
customerReviews: json['customerReviews'] ?? [],
);
}
any feedback or input would be very appreciated! Cheers
The forEach should be replaced by map(...).toList() like the following code snippet:
List<RestaurantModel> restaurants = result['restaurants'].map((json) {
return RestaurantModel.fromJson(json: json);
}).toList();
This is because forEach returns void and it cannot be assigned to anything. On the other hand, map returns a Iterable<RestaurantModel> and it's just a matter of converting it to list with the toList() method.
This is my model class and I am trying to get all the data but getting error and don't know why.
HomePageModel homePageModelFromJson(String str) => HomePageModel.fromJson(json.decode(str));
String homePageModelToJson(HomePageModel data) => json.encode(data.toJson());
class HomePageModel with ChangeNotifier {
HomePageModel({
this.data,
});
List<Datum>? data;
factory HomePageModel.fromJson(Map<String, dynamic> json) => HomePageModel(
data: List<Datum>.from(json["data"]!.map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data!.map((x) => x.toJson())),
};
}
class Datum {
Datum({
this.schoolid,
this.name,
this.logo,
this.address,
this.contact,
this.principalname,
this.principalcontact,
this.slogan,
this.webAddress,
this.description,
this.email,
this.pan,
this.establishedYear,
});
String? schoolid;
String? name;
String? logo;
String? address;
String? contact;
String? principalname;
String? principalcontact;
String? slogan;
String? webAddress;
String? description;
String? email;
String? pan;
int? establishedYear;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
schoolid: json["schoolid"],
name: json["name"],
logo: json["logo"],
address: json["address"],
contact: json["contact"],
principalname: json["principalname"],
principalcontact: json["principalcontact"],
slogan: json["slogan"],
webAddress: json["web_address"] == null ? null : json["web_address"],
description: json["description"] == null ? null : json["description"],
email: json["email"],
pan: json["pan"],
establishedYear: json["established_year"],
);
Map<String, dynamic> toJson() => {
"schoolid": schoolid,
"name": name,
"logo": logo,
"address": address,
"contact": contact,
"principalname": principalname,
"principalcontact": principalcontact,
"slogan": slogan,
"web_address": webAddress == null ? null : webAddress,
"description": description == null ? null : description,
"email": email,
"pan": pan,
"established_year": establishedYear,
};
}
This is how I am trying to fetch data:
class HomePageModels with ChangeNotifier{
List<HomePageModel> _hItem = [];
List<HomePageModel> get hItem{
return [..._hItem];
}
Future<void> getHomeData(BuildContext context) async{
const url = "https://shikshyasoftware.com.np/CoreApplicationandAPIService-4617993073/api/school";
try{
// EasyLoading.show(status: 'Loading...');
final response = await http.get(Uri.parse(url));
final extractedData = json.decode(response.body);
List<HomePageModel> loadedHomeData = [];
if(extractedData == null){
return;
}
if(response.statusCode == 200){
print(extractedData);
}
extractedData.forEach((element){
loadedHomeData.add(HomePageModel.fromJson(element));
});
_hItem = loadedHomeData;
// EasyLoading.showSuccess("data fetched sucessfull");
notifyListeners();
}catch(e){
rethrow;
}
}
}
But I am getting error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type '(dynamic) => Null' is not a subtype of type '(String, dynamic) => void' of 'f'
The problem is the way you are trying to parse the data, you don't need to loop over every element to parse it, in your model just make it return a list type like this,
class HomePageModel with ChangeNotifier {
List<Datum>? data;
HomePageModel({this.data});
HomePageModel.fromJson(Map<String, dynamic> json) {
if (json['data'] != null) {
data = <Datum>[];
json['data'].forEach((v) {
data!.add(new Datum.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 Datum {
Datum({
this.schoolid,
this.name,
this.logo,
this.address,
this.contact,
this.principalname,
this.principalcontact,
this.slogan,
this.webAddress,
this.description,
this.email,
this.pan,
this.establishedYear,
});
String? schoolid;
String? name;
String? logo;
String? address;
String? contact;
String? principalname;
String? principalcontact;
String? slogan;
String? webAddress;
String? description;
String? email;
String? pan;
int? establishedYear;
Datum.fromJson(Map<String, dynamic> json) {
schoolid = json["schoolid"];
name = json["name"];
logo = json["logo"];
address = json["address"];
contact = json["contact"];
principalname = json["principalname"];
principalcontact = json["principalcontact"];
slogan = json["slogan"];
webAddress = json["web_address"];
description = json["description"];
email = json["email"];
pan = json["pan"];
establishedYear = json["established_year"];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['schoolid'] = this.schoolid;
data['name'] = this.name;
data['logo'] = this.logo;
data['address'] = this.address;
data['contact'] = this.contact;
data['principalname'] = this.principalname;
data['principalcontact'] = this.principalcontact;
data['slogan'] = this.slogan;
data['web_address'] = this.webAddress;
data['description'] = this.description;
data['email'] = this.email;
data['pan'] = this.pan;
data['established_year'] = this.establishedYear;
return data;
}
}
and in your view model you can just parse the extracted data from response.body like this,
class HomePageModels with ChangeNotifier {
HomePageModel? _hItem;
HomePageModel get hItem {
return _hItem!;
}
Future<void> getHomeData(BuildContext context) async {
const url =
"https://shikshyasoftware.com.np/CoreApplicationandAPIService-
4617993073/api/school";
try {
// EasyLoading.show(status: 'Loading...');
final response = await http.get(Uri.parse(url));
final extractedData = json.decode(response.body);
if (extractedData == null) {
return;
}
if (response.statusCode == 200) {
print(extractedData);
}
HomePageModel loadedHomeData =
HomePageModel.fromJson(extractedData);
_hItem = loadedHomeData;
// EasyLoading.showSuccess("data fetched sucessfull");
notifyListeners();
} catch (e) {
rethrow;
}
}
}
getHomeData(BuildContext context) async {
const url =
"https://shikshyasoftware.com.np/CoreApplicationandAPIService-4617993073/api/school";
try {
// EasyLoading.show(status: 'Loading...');
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final extractedData = json.decode(response.body);
List loadedHomeData = extractedData;
_hItem = loadedHomeData.map((e) => HomePageModel.fromJson(e)).toList();
}
notifyListeners();
return _hItem;
} catch (e) {
rethrow;
}
}
I am uploading images to a storageAPI using POST method with content-type of multipart/form-data. The api returns an object response that looks as below:
{
"id": "6d50c066-cf65-4748-8b9a-183c3526f49b",
"name": "hotel_6.jpg",
"fileKey": "lv/im/5d9feb8e-2ea8-439d-a550-1e937081e085-hotel_6.jpg",
"fileExtension": ".jpg",
"mimeType": "image/jpeg",
"catalogueUrl": {
"mainUrl": "https://xy.abc.com/lv/im/5d9feb8e-2ea8-439d-a550-1e937081e085-hotel_6.jpg",
"thumbnailUrls": []
},
"createdAt": "2021-11-25T06:40:40.0869466+00:00"
}
How can I extract the variable "mainUrl" from the response so that I can assign its value to the _pictureController? Here is what I have done:
uploadFile() async {
var accessToken = await sharedPref.read(key);
var postUrl = '$baseUrl/catalogue?thumbnail=${param.thumbnailTrueFalse}';
Map < String, String > headers = {
"Authorization": "Bearer $accessToken",
};
// multipart request object
var request = http.MultipartRequest("POST", Uri.parse(postUrl));
request.headers.addAll(headers);
// add selected file with request
request.files.add(http.MultipartFile("file", imageStream, imageSize,
filename: imageName));
// Send request
var response = await request.send();
// Read response
var result = await response.stream.bytesToString();
print('readResponse: $result');
if (response.statusCode == 200) {
var data = StorageResponse.fromJson(jsonDecode(result));
print('data: $data');
setState(() {
_pictureController.text = data.catalogueUrl!.mainUrl!;
});
return data;
} else {
throw Exception('Failed to upload photo.');
}
}
The "StorageResponse" Class is as follows:
#JsonSerializable()
class StorageResponse {
var id;
var name;
var fileKey;
var fileExtension;
var mimeType;
Catalogue ? catalogueUrl;
var createdAt;
StorageResponse({
this.id,
this.name,
this.fileKey,
this.fileExtension,
this.mimeType,
this.catalogueUrl,
this.createdAt,
});
factory StorageResponse.fromJson(Map < String, dynamic > json) =>
_$StorageResponseFromJson(json);
Map < String, dynamic > toJson() => _$StorageResponseToJson(this);
#override
toString() {
String output =
'{id:${this.id},name:${this.name},fileKey: ${this.fileKey},fileExtension:${this.fileExtension},mimeType: ${this.mimeType}mimeType},catalogueUrl: ${this.catalogueUrl},,createdAt: ${this.createdAt}}';
return output;
}
}
You can use the following structure to convert a Json file to a class, and vice versa.
The following structure works properly.
import 'dart:convert';
class StorageResponse {
final String id;
final String name;
final String fileKey;
final String fileExtension;
final String mimeType;
Catalogue catalogueUrl;
final DateTime createdAt;
StorageResponse(
this.id,
this.name,
this.fileKey,
this.fileExtension,
this.mimeType,
this.catalogueUrl,
this.createdAt,
);
factory StorageResponse.fromMap(Map<String, dynamic> json) {
return StorageResponse(
json['id'],
json['name'],
json['fileKey'],
json['fileExtension'],
json['mimeType'],
Catalogue.fromMap(json['Catalogue']),
DateTime.parse(json['createdAt']));
}
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'fileKey': fileKey,
'fileExtension': fileExtension,
'mimeType': mimeType,
'Catalogue': catalogueUrl.toJson(),
'createdAt': createdAt
};
#override
toString() {
String output =
'{id:${this.id},name:${this.name},fileKey: ${this.fileKey},fileExtension:${this.fileExtension},mimeType: ${this.mimeType}mimeType},catalogueUrl: ${this.catalogueUrl},,createdAt: ${this.createdAt}}';
return output;
}
}
class Catalogue {
final String mainUrl;
final List<String> thumbnailUrls;
Catalogue(this.mainUrl, this.thumbnailUrls);
factory Catalogue.fromMap(Map<String, dynamic> json) {
return Catalogue(json['mainUrl'], jsonDecode(json['thumbnailUrls']));
}
Map<String, dynamic> toJson() =>
{'mainUrl': mainUrl, 'thumbnailUrls': jsonEncode(thumbnailUrls)};
}
for use
if (response.statusCode == 200) {
var data = StorageResponse.fromMap(jsonDecode(result));
print('data: $data');
setState(() {
_pictureController.text = data.catalogueUrl!.mainUrl!;
});
return data;
} else {
throw Exception('Failed to upload photo.');
}
I have a flutter application, which uses some server APIs.
When there is a successful response from the server, it would return json back:
{"success": true, "message": "success", "data": {"id": "21EE"} }
However, when there is failure, it would return:
{"success": false, "message": "failure"}
For more strict-typed use of flutter, I try to model the response.
Here is my try:
class ServerResponse {
final bool success;
final String message;
ServerResponse({
required this.success,
required this.message,
});
}
class _AuthAutenticationData {
final String id;
_AuthAutenticationData({
required this.id,
});
}
class AutoAuthenticateResponse extends ServerResponse {
final _AuthAutenticationData? data;
AutoAuthenticateResponse({
required success,
required message,
this.data,
}) : super(success: success, message: message);
}
Now, I have a function which calls a specific API:
Future<void> autoAuth() async {
final url = Uri.parse('${this._baseURL.toString()}/auto-auth');
try {
final response = await http.post(url, headers: {
'Authorization': 'SXXX',
});
print(response.body);
final AutoAuthenticateResponse responseBody = json.decode(response.body);
if (responseBody.success) {
return setUser(new User(id: responseBody.data!.id));
}
setUser(null);
} catch (error) {
print(error);
setUser(null);
}
}
Some code is irrelevant, but bottom line is that I receive the following error in the line: final AutoAuthenticateResponse responseBody = json.decode(response.body);:
I/flutter (14139): type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'AutoAuthenticateResponse'
I guess my solution is bad. Any advice how to fix it?
Well, you can use nullsafety feature for this. Since it's only if when the failure the data is not being returned.
{"success": true, "message": "success", "data": {"id": "21EE"} }
you can use this :
https://meruya-techhnology.github.io/json-to-dart/
Then the result will be a 2 class
class YourClass {
final bool success;
final String message;
final Data? data;
YourClass({this.success, this.message, this.data});
factory YourClass.fromJson(Map<String, dynamic> json) => YourClass(
success : json['success'],
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['success'] = this.success;
data['message'] = this.message;
if (this.data != null) {
data['data'] = this.data.toJson();
}
return data;
}
}
And
class Data {
String id;
Data({this.id});
Data.fromJson(Map<String, dynamic> json) {
id = json['id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
return data;
}
}
Then you can use it like this :
Future<void> autoAuth() async {
final url = Uri.parse('${this._baseURL.toString()}/auto-auth');
try {
final response = await http.post(url, headers: {
'Authorization': 'SXXX',
});
debugPrint(response.body);
final responseBody = YourClass.fromJson(response.body)
if (responseBody.success) {
return setUser(new User(id: responseBody.data!.id));
}
setUser(null);
} catch (error) {
print(error);
setUser(null);
}
}
another advice is use debugPrint instead of print, here you can read more : https://medium.com/flutter-community/debugprint-and-the-power-of-hiding-and-customizing-your-logs-in-dart-86881df05929
Use this link to generate models for your response