Integrasi API: Menampilkan List Produk (GET)
Tujuan Pembelajaran
Setelah mengikuti materi ini, siswa mampu: 1. Menggunakan package HTTP dan flutter_dotenv di Flutter. 2. Mengamankan URL API menggunakan file .env. 3. Mengubah format JSON menjadi Dart Model menggunakan app.quicktype.io. 4. Membuat Service untuk mengambil data produk dari internet. 5. Menampilkan data dari API ke dalam UI menggunakan FutureBuilder.
Pertanyaan Pemantik
Di bab sebelumnya, kita membuat tampilan Toko Online dengan data "palsu" (dummy data) yang kita ketik manual di kodingan.
Bagaimana caranya agar aplikasi kita bisa menampilkan barang dagangan yang sesungguhnya dari database server?
1. Persiapan: Request URL
Kita sudah disiapkan API Server Toko Online yang berisi daftar produk.
URL API: https://online-shop-golang.vercel.app/products
Method: GET
Silakan buka URL tersebut di browser atau Thunder Client. Kalian akan melihat data seperti ini:
[
{
"id": 1,
"name": "Keyboard Mechanical Gaming red",
"category": "Gaming",
"price": 750000,
"image_url": "https://m.media-amazon.com/images/...",
"description": "Keyboard mechanical RBG...",
"rating": 4.7
},
...
]
2. Membuat Model Data (Cara Cepat)
Menulis model manual itu lama dan rawan salah ketik. Kita akan gunakan tools Quicktype untuk membuat model secara otomatis.
Langkah-langkah:
1. Copy SEMUA teks JSON dari URL di atas.
2. Buka situs app.quicktype.io.
3. Pastikan setting di sebelah kanan:
* Name: Product
* Language: Dart
* Null Safety: Aktif (Make properties required/optional sesuai kebutuhan, biasanya default sudah oke).
4. Paste JSON di kolom kiri.
5. Copy kode Dart yang muncul di kolom kanan.
Implementasi di Project:
1. Buat file baru: lib/models/product_model.dart.
2. Paste kode dari Quicktype ke file tersebut.
Contoh hasil (disederhanakan):
import 'dart:convert';
List<Product> productFromJson(String str) => List<Product>.from(json.decode(str).map((x) => Product.fromJson(x)));
String productToJson(List<Product> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Product {
int id;
String name;
String category;
int price;
String imageUrl;
String description;
double rating;
Product({
required this.id,
required this.name,
required this.category,
required this.price,
required this.imageUrl,
required this.description,
required this.rating,
});
factory Product.fromJson(Map<String, dynamic> json) => Product(
id: json["id"],
name: json["name"],
category: json["category"],
price: json["price"],
imageUrl: json["image_url"], // Perhatikan ini otomatis menyesuaikan snake_case ke camelCase
description: json["description"],
rating: json["rating"]?.toDouble(),
);
// ... method toJson
}
3. Konfigurasi Environment & Package
Agar url API kita rapi dan aman, kita akan menyimpannya dalam file terpisah menggunakan package flutter_dotenv.
A. Instalasi Package
- Buka terminal di VS Code.
- Jalankan perintah:
flutter pub add http flutter_dotenv - Tunggu proses selesai.
B. Membuat File .env
- Buat file baru di root folder project (sejajar dengan
pubspec.yaml), beri nama.env. - Isi file tersebut dengan:
API_URL=https://online-shop-golang.vercel.app
C. Mendaftarkan Assets
- Buka file
pubspec.yaml. - Cari bagian
assets(biasanya dikomentari). - Tambahkan
.envdi sana:flutter: assets: - .env
D. Inisialisasi di Main
- Buka
lib/main.dart. -
Ubah fungsi
main()menjadiasyncdan load dotenv:import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; // Import ini Future<void> main() async { await dotenv.load(fileName: ".env"); //runappnya jangan diubah }
4. Membuat Service API
Kita akan membuat "Pelayan" yang mengambil data, tapi sekarang URL-nya diambil dari .env.
- Buat folder
lib/services. - Buat file
lib/services/product_service.dart. - Tulis kode berikut:
import 'package:http/http.dart' as http;
import 'package:flutter_dotenv/flutter_dotenv.dart';
import '../models/product_model.dart';
class ProductService {
// Ambil URL dari .env
final String baseUrl = dotenv.env['API_URL'] ?? 'https://online-shop-golang.vercel.app';
// Fungsi untuk mengambil list produk
Future<List<Product>> getProducts() async {
// 1. Tentukan alamat lengkap (gunakan baseUrl)
var url = Uri.parse('$baseUrl/products');
// 2. Lakukan Request GET
var response = await http.get(url);
// 3. Cek status apakah berhasil (200 OK)
if (response.statusCode == 200) {
// 4. Ubah respon JSON mentah menjadi List Objek Product
return productFromJson(response.body);
} else {
// Jika gagal
throw Exception('Gagal mengambil data produk');
}
}
}
5. Integrasi ke UI (FutureBuilder)
Sekarang kita akan menghubungkan Service tadi ke Halaman Produk (ui yang sudah kalian buat sebelumnya).
Kita akan menggunakan FutureBuilder. Widget ini sangat sakti karena bisa menangani 3 kondisi otomatis:
1. Loading: Saat data sedang diambil.
2. Success: Saat data berhasil didapat.
3. Error: Saat data gagal diambil (misal tidak ada internet).
Langkah-langkah:
1. Buka file halaman produk kalian (misalnya home_page.dart atau product_list_page.dart).
2. Panggil service di dalam class.
3. Ganti ListView manual kalian dengan FutureBuilder.
Contoh Kode:
import 'package:flutter/material.dart';
import '../services/product_service.dart';
import '../models/product_model.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// Panggil service
final ProductService productService = ProductService();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Toko Online API")),
body: FutureBuilder<List<Product>>(
// Minta data ke service
future: productService.getProducts(),
builder: (context, snapshot) {
// 1. KONDISI LOADING
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
// 2. KONDISI ERROR
if (snapshot.hasError) {
return Center(child: Text("Error: ${snapshot.error}"));
}
// 3. KONDISI SUKSES (Data Ada)
if (snapshot.hasData) {
List<Product> products = snapshot.data!;
return GridView.builder( // atau ListView.builder
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.7,
),
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
// TAMPILKAN CARD PRODUK KALIAN DISINI
return Card(
child: Column(
children: [
// Gambar dari Network
Expanded(
child: Image.network(
product.imageUrl,
fit: BoxFit.cover,
// Tambahkan errorBuilder untuk jaga-jaga gambar rusak
errorBuilder: (ctx, error, stack) => const Icon(Icons.broken_image),
),
),
Text(product.name),
Text("Rp ${product.price}"),
],
),
);
},
);
}
return const Center(child: Text("Tidak ada data."));
},
),
);
}
}
Tugas Praktikum
- Lakukan langkah-langkah configurasi
.envdengan teliti. - Pastikan Internet Aktif saat menjalankan aplikasi.
- Jika terjadi error "File .env not found", coba stop dan run ulang project kalian.
- Tantangan: Tambahkan fitur RefreshIndicator agar user bisa swipe ke bawah untuk reload data!
Ringkasan
- flutter_dotenv digunakan untuk menyimpan konfigurasi rahasia/global.
- FutureBuilder memudahkan kita menangani state asynchronous (Loading, Error, Data).