I am trying to call an API and get a list of products in my example. Getting a single product and convert it into a dart object works already. However when I try to get a list of products I can't manage to do that.
I read the official documentation of Flutter but they only show how to retrieve 1 item from the API instead of a list of items...
I checked a lot of tutorials but it does not seem to work that well either. I never thought this would be that hard.
Structure
I got a product_service that is responsible for the API call and I got a product model. Which contains the properties (name for example).
How does the code look like?
product_service.dart
// Endpoint : Get product by id
Future<Product> getProductById(int productId) async {
String basicAuth =
'Basic ' base64Encode(utf8.encode('$username:$password'));
print(basicAuth);
var response = await http.get(
Uri.parse(
'https://website/wp-json/wc/v3/products/${productId}'),
headers: <String, String>{'authorization': basicAuth});
if (response.statusCode == 200) {
//return response.body;
return Product.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load product');
}
// Endpoint : Get all products
Future<List<Product>> getAllProducts() async {
String basicAuth =
'Basic ' base64Encode(utf8.encode('$username:$password'));
print(basicAuth);
Product? product;
var r = await http.get(
Uri.parse(
'https://website/wp-json/wc/v3/products?post_per_page=1'),
headers: <String, String>{'authorization': basicAuth});
if (r.statusCode == 200) {
print(r.body);
product = Product().productsFromJson(jsonDecode(r.body));
}
return [];
}
product model
class Product {
// Properties
String name;
String description;
String price;
List<dynamic> images;
int stockQuantity;
List<Category> categories;
// Constructor
Product(
{required this.name,
required this.description,
required this.price,
required this.stockQuantity,
required this.images,
required this.categories});
// Make a product object from json
factory Product.fromJson(Map<String, dynamic> json) {
List<Category> categorieList = [];
for (var cat in json['categories']) {
Category category = Category(name: cat['name'], slug: cat['slug']);
categorieList.add(category);
}
return Product(
name: json['name'],
description: json['description'],
price: json['price'],
stockQuantity: json['stock_quantity'],
images: json['images'],
categories: categorieList);
}
// Make list of products from json
List<Product> productsFromJson(Map<String, dynamic> json) {
List<Product> products = [];
json.forEach((key, value) {
Product p = Product.fromJson(value);
products.add(p);
});
return products;
}
What goes wrong?
I kept some code out to make the code more readable for everyone. I tried to add an extra function in my product model but I cannot call it in my product_service.dart. This is because the parameters like name and price is required. I can make it all nullable and do the following:
String? name;
But I am not sure if this is a best practice to do. What is the best practice for this problem?
I also have a question about Future. Why should you use future when someone can use Async and Await without Future and then return a List?
Thank you all!
CodePudding user response:
When you edit the model class like this the problem will be solved,
class Product {
// Properties
String name;
String description;
String price;
List<dynamic> images;
int stockQuantity;
List<Category> categories;
// Constructor
Product(
{required this.name,
required this.description,
required this.price,
required this.stockQuantity,
required this.images,
required this.categories});
factory Product.fromJson(Map<String, dynamic> json) =>
Product(
name:json["name"],
description:json["description"],
price:json["price"],
stockQuantity:json["stockQuantity"],
images:json["images"],
categories: List<Category>.from(
json["categories"].map((x) => Category.fromJson(x))),
);
}
Category model should be like this:
class Category {
// Properties
String categoryName;
String categoryDescription;
String categoryImages;
// Constructor
Category({
required this.categoryName,
required this.categoryDescription,
required this.categoryImages,
});
factory Category.fromJson(Map<String, dynamic> json) => Category(
categoryName: json["categoryName"],
categoryDescription: json["categoryDescription"],
categoryImages: json["categoryImages"],
);
}
CodePudding user response:
Future<List<Product>> getAllProducts() async {
String basicAuth =
'Basic ' base64Encode(utf8.encode('$username:$password'));
print(basicAuth);
//Removed the product type
var r = await http.get(
Uri.parse(
'https://website/wp-json/wc/v3/products?post_per_page=1'),
headers: <String, String>{'authorization': basicAuth});
//Made your code a little more readable here
if (r.statusCode == 200) {
String data = response.body;
var decodedData = json.decode(data);
return decodedData;
}else {
return r.statusCode;
}
//Now to get a list of products you need a new function
Future<List<Product>> getProductsList () async{
//Here we will call the data from the API into a variable
var products = await getAllProducts();
List<Product> productList = [];
for( p in products){
Product _product = Product(
name : p['name'],
description :p['description'],
//I trust you get the gist here, do this for all map values
);
//Here we are going to add each of the items to the list above
productList.add(Product.fromjson(p));
}
return productList;
}
You will need to make use of a FutureBuilder of type {Product} to display your items