flutter search from API Json - flutter

Im trying to make a searchbar that fetch data from mysql , but i have a problem that when i call data fetch function it returns
Instance of '_Future<List>'
this is my code
Future<List<Students>> getStudents(String id) async {
var url = 'http://localhost/getStudents.php';
final response = await http.post(Uri.parse(url), body: {
'id':id,
});
var res = jsonDecode(response.body)['fname'] as List;
if (response.statusCode == 200) {
return res.map((std) => Students.fromJson(std)).toList();
}else {
throw Exception('Failed to load shows');
}
}
my class :
class Students{
final int id;
final String fname;
final String sname;
final String tname;
const Students( {
required this.id,
required this.sname,
required this.tname,
required this.fname,
});
factory Students.fromJson(Map<String, dynamic> json) => Students(
id: json['Id'],
sname: json['secname'],
tname:json['thirdname'] ,
fname: json['firstname'],
);
}

getStudents is a future function and you need to await for it:
List<Students> result = await getStudents('');

Related

Flutter: problem in fetching data: type 'Null' is not a subtype of type 'String' error

I am trying to fetch google book search api data.
https://www.googleapis.com/books/v1/volumes?q=%EA%B2%BD%EC%A0%9C
I followed this one:
https://docs.flutter.dev/cookbook/networking/fetch-data
My class:
class Book {
final String id;
final String title;
final List<String> authors;
const Book({
required this.id,
required this.title,
required this.authors,
});
factory Book.fromJson(Map json) {
return Book(
id: json['id'],
title: json['title'],
authors: json['author'],
);
}
}
request data:
late Future<List<Book>> futureBooks;
Future<List<Book>> fetchBooks() async {
Uri url = Uri.parse(
'https://www.googleapis.com/books/v1/volumes?q=경제 경영'); //&maxResults=1
final response = await http.get(url);
if (response.statusCode == 200) {
var json = jsonDecode(response.body);
List<dynamic> items = json['items'];
List<Book> books = (items.map((item) {
return Book.fromJson(item);
})).toList();
return books;
} else {
throw Exception('Failed to load Books');
}
}
#override
void initState() {
super.initState();
futureBooks = fetchBooks();
}
I think I have same issue with this.
How to solve the "Type Null is not a subtype of type ..." error?
So I appended [?] for fields.
class Book {
final String? id;
final String? title;
final List<String>? authors;
It still give me null.
my code:
https://github.com/kangsudal/millie/blob/7f1f912c5a0eba0fe09de67c1c729be73b660da1/lib/screens/0_today/tab_widdget/tab_now.dart#L62
how to get data?
because title and author is not inside item object, it inside volumeInfo, so you much change fromJson method of your Book class to
factory Book.fromJson(Map json) {
return Book(
id: json['id'],
title: json['volumeInfo']['title'],
authors: json['volumeInfo']['author'],
);
}

Error fetching API / A value of type 'List<Heroes>' can't be returned from the method 'getHeroes' because has a return type of 'Future<List<String>?>

im new in Dart/Flutter and im struggling with consuming API, here is my file thats inside my model folder:
List<Heroes> heroesFromJson(String str) =>
List<Heroes>.from(json.decode(str).map((x) => Heroes.fromJson(x)));
String heroesToJson(List<Heroes> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Heroes {
Heroes({
required this.id,
required this.name,
required this.localizedName,
required this.primaryAttr,
required this.attackType,
required this.roles,
});
int id;
String name;
String localizedName;
String primaryAttr;
String attackType;
List<String> roles;
factory Heroes.fromJson(Map<String, dynamic> json) => Heroes(
id: json["id"],
name: json["name"],
localizedName: json["localized_name"],
primaryAttr: json["primary_attr"],
attackType: json["attack_type"],
roles: List<String>.from(json["roles"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"localized_name": localizedName,
"primary_attr": primaryAttr,
"attack_type": attackType,
"roles": List<dynamic>.from(roles.map((x) => x)),
};
}
And here is where im getting the error, inside services folder:
class DotaServices {
Future<List<String>?> getHeroes() async {
var client = http.Client();
var url = Uri.parse('https://api.opendota.com/api/heroes');
var response = await client.get(url);
if (response.statusCode == 200) {
var json = response.body;
return heroesFromJson(json);
}
}
}
The error is occuring in that line:
return heroesFromJson(json);
And the message that appears is:
A value of type 'List<Heroes>' can't be returned from the method 'getHeroes' because it has a return type of 'Future<List<String>?>'.
how to solve it? Im struggling real hard on this :/
Your method returns a list of heroes... so... you need to return a list of heroes:
Future<List<String>?> getHeroes() async {
needs to be
Future<List<Heroes>?> getHeroes() async {
heroesFromJson returns a list of heroes so getHeroes has to return a list of heroes:
Future<List<Heroes>?> getHeroes()
Also, your method heroesFromJson returns a List<Heroes> not nullable, but your method getHeroes() return a List<Heroe>? which is nullable.
You either can make your return from heroesFromJson a nullable list List<T>? or your return from getHeroes() a non-nullable list List
Be careful making your List nullable or non-nullable List<Hero>?, not your Hero List<Hero?>
It seems to me that such code should work more reliably.
return Hero.fromJsonList(json as List);
This small example (including function main) was generated with a very small script.
import 'dart:convert';
import 'package:http/http.dart' as http;
void main(List<String> args) async {
final svc = DotaServices();
final heroes = await svc.getHeroes();
print('Heroes: ${heroes.length}');
}
class DotaServices {
Future<List<Hero>> getHeroes() async {
final client = http.Client();
final url = Uri.parse('https://api.opendota.com/api/heroes');
final response = await client.get(url);
if (response.statusCode == 200) {
final source = response.body;
final json = jsonDecode(source);
return Hero.fromJsonList(json as List);
}
throw StateError('Http error: ${response.statusCode}');
}
}
class Hero {
Hero(
{required this.id,
required this.name,
required this.localizedName,
required this.primaryAttr,
required this.attackType,
required this.roles});
factory Hero.fromJson(Map json) {
return Hero(
id: json['id'] as int,
name: json['name'] as String,
localizedName: json['localized_name'] as String,
primaryAttr: json['primary_attr'] as String,
attackType: json['attack_type'] as String,
roles: json['roles'] == null
? []
: (json['roles'] as List).map((e) => e as String).toList(),
);
}
final int id;
final String name;
final String localizedName;
final String primaryAttr;
final String attackType;
final List<String> roles;
static List<Hero> fromJsonList(List json) {
return json.map((e) => Hero.fromJson(e as Map)).toList();
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'localized_name': localizedName,
'primary_attr': primaryAttr,
'attack_type': attackType,
'roles': roles,
};
}
static List<Map<String, dynamic>> toJsonList(List<Hero> list) {
return list.map((e) => e.toJson()).toList();
}
}
Using this codegen script you can generate the models and serializers.
It also generates a working example.
import 'dart:io';
import 'package:object_serializer/json_serializer_generator.dart';
import 'package:yaml/yaml.dart';
void main() {
final classes = loadYaml(_classes) as Map;
final g = JsonSerializerGenerator();
final classesCode = g.generateClasses(classes);
final values = {
'classes': classesCode,
};
var source = g.render(_template, values);
source = g.format(source);
File('bin/stackoverflow.dart').writeAsStringSync(source);
}
const _classes = '''
Hero:
fields:
id: int
name: String
localizedName: {type: String, alias: localized_name}
primaryAttr: {type: String, alias: primary_attr}
attackType: {type: String, alias: attack_type}
roles: List<String>
''';
const _template = r'''
import 'dart:convert';
import 'package:http/http.dart' as http;
void main(List<String> args) async {
final svc = DotaServices();
final heroes = await svc.getHeroes();
print('Heroes: ${heroes.length}');
}
class DotaServices {
Future<List<Hero>> getHeroes() async {
final client = http.Client();
final url = Uri.parse('https://api.opendota.com/api/heroes');
final response = await client.get(url);
if (response.statusCode == 200) {
final source = response.body;
final json = jsonDecode(source);
return Hero.fromJsonList(json as List);
}
throw StateError('Http error: ${response.statusCode}');
}
}
{{classes}}
''';

type 'Null' is not a subtype of type 'List<RestaurantModel>'

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.

_CastError (type 'String' is not a subtype of type 'List<dynamic>' in type cast)

I have done various ways to create a cached product list then display with a list, but till now still not working, can anyone help me
My Json fromCache
"[{"id":"2911","nama":"Abcd1","url":"myUrl"},{"id":"2910","nama":"Abcd2","url":"myUrl"},{"id":"2911","nama":"Abcd3","url":"myUrl"},{"id":"2549","nama":"Abcd4","url":"myUrl"}]"
My Code
Future<List<ApiBookmark>> fetchApiBookmark() async {
var adaCache = await APICacheManager().isAPICacheKeyExist('bookmark');
if (adaCache) {
print('ada');
var cacheData = await APICacheManager().getCacheData('bookmark');
var fromCache = '[' + cacheData.syncData + ']';
List jsonResponse = fromCache as List;
return jsonResponse
.map((e) => ApiBookmark(id: e.id, nama: e.nama, url: e.url))
.toList();
} else {
print('tidak ada');
throw Exception('Failed to load bookmark');
}
}
class ApiBookmark {
final String id;
final String nama;
final String url;
const ApiBookmark({
required this.id,
required this.nama,
required this.url,
});
factory ApiBookmark.fromJson(Map<String, dynamic> json) {
return ApiBookmark(
id: json['id'],
nama: json['nama'],
url: json['url'],
);
}
}
Try this
List<ApiBookmark> listApi = <ApiBookmark>[];
Future<List<ApiBookmark>> fetchApiBookmark() async {
listApi.clear();
var fromCache = '''[{"id":"2911","nama":"Abcd1","url":"myUrl"},
{"id":"2910","nama":"Abcd2","url":"myUrl"},
{"id":"2911","nama":"Abcd3","url":"myUrl"},
{"id":"2549","nama":"Abcd4","url":"myUrl"}]''';
final jsonData = json.decode(fromCache);
for (var item in jsonData) {
listApi.add(ApiBookmark.fromJson(item));
}
for (var item in listApi) {
print("${item.id} ${item.nama} ${item.url}");
}
return listApi;
}
then you can implement "APICacheManager()"

How to extract data from a multipart/form-data response?

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.');
}