Menghubungkan Flutter ke HTTP & REST API
Pada pertemuan ini, kita akan belajar bagaimana aplikasi Flutter dapat berkomunikasi dengan server, mengambil data secara realtime dari…
Menghubungkan Flutter
ke HTTP & REST API
Pada pertemuan ini, kita akan belajar bagaimana aplikasi Flutter dapat berkomunikasi dengan server, mengambil data secara realtime dari internet, melakukan parsing JSON, serta menangani proses loading dan error.
Gimana Aplikasi Bisa Ambil Data dari Internet?
Aplikasi seperti Instagram atau Google Maps bisa menampilkan data terbaru karena melakukan HTTP Request ke server lewat internet. Server lalu mengirim balik response berupa data, biasanya dalam format JSON. Di Flutter, proses ini dilakukan secara asynchronous menggunakan async dan await supaya UI tetap berjalan lancar saat menunggu data.
Beberapa konsep penting:
- HTTP → komunikasi antara aplikasi dan server
- REST API → aturan endpoint seperti
/usersatau/news - JSON → format data key-value dari server
- Async/Await → menjalankan proses network tanpa nge-freeze UI
Method HTTP yang paling sering dipakai:
GET→ ambil dataPOST→ tambah dataPUT→ update dataDELETE→ hapus data
Alur sederhananya:
Flutter kirim request → server balas JSON + status code → Flutter parsing JSON → data ditampilkan ke UI menggunakan FutureBuilder.
Persiapan sebelum coding
Di pertemuan ini, kita sudah menyiapkan template project news, jadi kalian tidak perlu membuat project dari nol. Tugas kita nanti adalah menyambungkan aplikasi ke API dan menampilkan data agar berjalan dengan baik.
Langkah pertama, ekstrak terlebih dahulu file project Flutter yang sudah diunduh, lalu buka file pubspec.yaml.
Tambahkan dependency http pada bagian dependencies seperti berikut:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.6
http: ^1.2.0 # ← tambahkan ini
Package http digunakan untuk melakukan HTTP request ke server atau API. Setelah itu, jalankan perintah berikut di terminal untuk mengunduh package:
flutter pub get
Izinkan akses internet (Android)
Buka file berikut:
android/app/src/main/AndroidManifest.xml
Lalu tambahkan permission internet di dalam tag <manifest>:
<manifest xmlns:android="...">
<!-- Tambahkan baris ini -->
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
...
</application>
</manifest>
Tanpa permission ini, aplikasi Android tidak bisa mengambil data dari internet.
Daftarkan diri dan dapat API Key
- Buka NewsAPI lalu klik tombol “Get API Key” di kanan atas.
- Isi form registrasi dengan First Name, Email address, dan Password. Pilih “I am an individual” dan gunakan email asli karena perlu verifikasi.
- Cek inbox email lalu klik link verifikasi dari NewsAPI sampai masuk ke dashboard.
- Salin API key yang muncul di dashboard. Bentuknya berupa string panjang seperti
a1b2c3d4e5f6... - Simpan API key tersebut untuk digunakan di kode Flutter.
Test Endpoint
Sekarang kita coba test endpoint langsung di browser. Ini cara paling cepat dan profesional untuk memastikan API benar-benar berfungsi.
Ketik URL berikut di search bar browser lalu ganti YOUR_KEY dengan API key milik kalian:
https://newsapi.org/v2/top-headlines?country=id&apiKey=YOUR_KEY
Endpoint seperti ini bisa kalian temukan di dokumentasi resmi NewsAPI Documentation
Kalau API berhasil terhubung, browser akan menampilkan response JSON seperti berikut:
{
"status": "ok",
"sources": [
{
"id": "abc-news",
"name": "ABC News",
"description": "Your trusted source for breaking news...",
"url": "https://abcnews.go.com",
"category": "general",
"language": "en",
"country": "us"
},
// ... sources/media lainnya
]
}
Jika muncul "status": "ok", berarti API key valid dan NewsAPI sudah siap digunakan di project Flutter kalian.
Konfigurasi API Key di Kode Flutter
Sekarang kita akan memasukkan API Key NewsAPI ke dalam project Flutter. Karena template project sudah disiapkan, kamu tidak perlu membuat file baru.
Buka file:
lib/news_services.dart
Di dalam class NewsService, cari variabel _apiKey lalu ganti dengan API key milikmu:
class NewsService {
// Ganti dengan API Key dari dashboard NewsAPI
static const String _apiKey = 'YOUR_API_KEY';
static const String _baseUrl = 'https://newsapi.org/v2';
// ... fungsi fetch
}
_baseUrl digunakan sebagai alamat dasar server NewsAPI. Pemisahan seperti ini membuat kode lebih rapi dan lebih mudah dikelola kalau suatu saat endpoint berubah.
Memahami Data Model (news_model.dart)
Data dari API awalnya masih berupa JSON mentah. Supaya lebih mudah digunakan di Flutter, data tersebut harus diubah menjadi object Dart. Proses ini disebut JSON Parsing.
Di file:
lib/news_model.dart
bagian terpentingnya adalah constructor fromJson():
NewsModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
description = json['description'];
url = json['url'];
category = json['category'];
language = json['language'];
country = json['country'];
}
Saat API mengirim response JSON, Flutter akan mengubahnya menjadi Map<String, dynamic> menggunakan jsonDecode().
fromJson() bertugas mengambil nilai dari setiap key JSON lalu memasukkannya ke dalam property object Dart secara otomatis.
Contohnya:
name = json['name'];
berarti data dari key "name" akan dimasukkan ke variabel name.
Setelah diparsing, data bisa diakses lebih nyaman menggunakan dot notation:
news.name
bukan:
news['name']
Proses Transformasi dan Filtering Data
Di file:
lib/news_services.dart
terdapat proses penting sebelum data dikirim ke UI:
return sourcesJson
.map((json) => NewsModel.fromJson(json))
.where((source) => source.name != '[Removed]')
.toList();
Baris ini melakukan tiga proses sekaligus.
.map()
Mengubah setiap JSON mentah menjadi object NewsModel.
.map((json) => NewsModel.fromJson(json))
Tanpa proses ini, data masih berupa Map biasa.
.where()
Digunakan untuk filtering data.
.where((source) => source.name != '[Removed]')
Kadang NewsAPI masih mengirim source lama yang sudah dihapus sistem dengan nama [Removed].
Filter ini membuang data rusak agar tidak tampil di aplikasi.
.toList()
Mengubah hasil akhir menjadi List<NewsModel>.
.toList()
Karena hasil .map() dan .where() masih berupa iterable, bukan list final.
Menampilkan Data dengan FutureBuilder
Halaman utama aplikasi dikontrol oleh:
lib/news_list_screen.dart
Karena aplikasi mengambil data dari internet, kita menggunakan StatefulWidget.
Saat halaman pertama dibuka, initState() otomatis dipanggil:
@override
void initState() {
super.initState();
_loadNews();
}
Fungsi _loadNews() menjalankan request API:
void _loadNews() {
setState(() {
_newsFuture = _newsService.fetchSources();
});
}
Kenapa Menggunakan FutureBuilder?
Karena request internet membutuhkan waktu.
FutureBuilder memantau status dari _newsFuture lalu otomatis memperbarui tampilan berdasarkan kondisi data.
FutureBuilder<List<NewsModel>>(
future: _newsFuture,
builder: (context, snapshot) {
// Loading
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
// Error
if (snapshot.hasError) {
return const Center(
child: Text('Gagal memuat berita'),
);
}
// Empty data
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(
child: Text('Tidak ada berita tersedia.'),
);
}
// Success
final news = snapshot.data!;
return ListView.builder(
itemCount: news.length,
itemBuilder: (context, index) {
// Render item berita
},
);
},
)
Empat Kondisi yang Ditangani FutureBuilder
Loading
Saat data masih diambil dari internet.
ConnectionState.waiting
UI menampilkan loading spinner.
Error
Saat request gagal.
snapshot.hasError
Misalnya:
- internet mati
- API key salah
- server error
Empty
Saat request berhasil tapi data kosong.
snapshot.data!.isEmpty
Success
Saat data berhasil diterima dan siap ditampilkan.
final news = snapshot.data!;
Pull-to-Refresh dengan RefreshIndicator
Supaya user bisa refresh berita terbaru cukup dengan swipe ke bawah, kita bungkus ListView menggunakan RefreshIndicator.
RefreshIndicator(
onRefresh: () async {
_loadNews();
},
child: ListView.builder(
itemCount: news.length,
itemBuilder: (context, index) {
// Render berita
},
),
)
Saat user menarik layar ke bawah:
_loadNews()dipanggil ulang.- API request dijalankan lagi.
- Data terbaru langsung muncul di layar.
Inilah alasan kombinasi FutureBuilder dan RefreshIndicator sangat sering dipakai di Flutter untuk aplikasi berbasis API realtime.

Tantangan
- Buat aplikasi daftar film menggunakan data api dari https://www.themoviedb.org
- Aplikasi dapat menampilkan daftar film hingga detail film
- Minimal data yang ditampilkan yaitu nama, deskripsi dan gambar
Daftar & Ambil API Key di TMDB
Buka TMDB Official Website lalu daftar atau login menggunakan akun kalian.
Setelah berhasil login:
- masuk ke menu Settings
- pilih API
- klik Create API Key
Isi data yang diminta lalu submit. Karena cuma untuk belajar, isi sederhana aja sudah cukup.
Contoh aman:
- Application Name →
Flutter Movie App - Application URL →
[https://example.com](https://example.com) - Type of Use →
Mobile Application - Application Summary →
Learning Flutter and REST API integration using TMDB API.
Setelah selesai, TMDB akan menampilkan API Key yang nanti digunakan di project Flutter untuk mengambil data film.
Tambahkan Package http
Buat project Flutter baru lalu buka file pubspec.yaml. Tambahkan dependency http pada bagian dependencies:
dependencies:
flutter:
sdk: flutter
http: ^1.2.1 # tambahkan baris ini
Setelah itu, jalankan perintah berikut di terminal:
flutter pub get
Susunan File yang Akan Dibuat
lib/
main.dart ← entry point aplikasi
movie_model.dart ← struktur data film
movie_service.dart ← logika pemanggilan API
movie_list_screen.dart ← halaman daftar film
movie_detail_screen.dart ← halaman detail film
Membuat MovieModel
Sebelum mengambil data dari API, kita perlu membuat model untuk menampung data film dari TMDB.
Endpoint /movie/popular dari TMDB mengembalikan data JSON seperti ini:
{
"results": [
{
"id": 1022789,
"title": "Inside Out 2",
"overview": "Teenager Riley's mind headquarters...",
"poster_path": "/vpnVM9B6NMmQpWeZvzLvDESb2QY.jpg",
"vote_average": 7.6,
"release_date": "2024-06-11"
}
]
}
Buat file baru:
lib/movie_model.dart
Lalu buat class berikut:
class MovieModel {
final int? id;
final String? title;
final String? overview;
final String? posterPath;
final double? voteAverage;
final String? releaseDate;
MovieModel({
this.id,
this.title,
this.overview,
this.posterPath,
this.voteAverage,
this.releaseDate,
});
factory MovieModel.fromJson(Map<String, dynamic> json) {
return MovieModel(
id: json['id'],
title: json['title'],
overview: json['overview'],
posterPath: json['poster_path'],
voteAverage: (json['vote_average'] as num?)?.toDouble(),
releaseDate: json['release_date'],
);
}
// URL lengkap poster film
String get posterUrl =>
'https://image.tmdb.org/t/p/w500$posterPath';
}
TMDB tidak mengirim URL gambar secara penuh. Field poster_path hanya berisi path seperti:
/abc.jpg
Karena itu kita perlu menggabungkannya dengan:
https://image.tmdb.org/t/p/w500
Getter posterUrl digunakan supaya URL gambar lengkap bisa dibuat otomatis saat digunakan di Flutter.
Membuat MovieService
File ini bertugas mengambil data film dari API TMDB lalu mengubah response JSON menjadi List<MovieModel>.
Buat file baru:
lib/movie_service.dart
isi dengan kode berikut:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'movie_model.dart';
class MovieService {
static const String _apiKey =
'GANTI_DENGAN_API_KEY_KAMU';
static const String _baseUrl =
'https://api.themoviedb.org/3';
// Ambil daftar film populer
Future<List<MovieModel>> fetchPopularMovies() async {
final uri = Uri.parse(
'$_baseUrl/movie/popular?api_key=$_apiKey&language=id-ID',
);
final response = await http.get(uri).timeout(
const Duration(seconds: 10),
onTimeout: () => throw Exception('Request timeout.'),
);
if (response.statusCode == 200) {
final Map<String, dynamic> data =
jsonDecode(response.body);
final List<dynamic> results = data['results'];
return results
.map((json) => MovieModel.fromJson(json))
.toList();
} else if (response.statusCode == 401) {
throw Exception('API Key tidak valid.');
} else {
throw Exception(
'Gagal memuat data. Status: ${response.statusCode}',
);
}
}
}
Jangan lupa ganti:
static const String _apiKey =
'GANTI_DENGAN_API_KEY_KAMU';
Fungsi fetchPopularMovies() bekerja dalam beberapa tahap:
- membuat URL endpoint TMDB
- mengirim HTTP GET request
- mengubah JSON menjadi
MovieModel - menangani error jika request gagal
Membuat Halaman Daftar Film
Halaman ini akan menjadi halaman utama aplikasi. Data film diambil dari API menggunakan FutureBuilder, lalu ditampilkan dalam bentuk list berisi poster, judul, dan rating film.
Buat file baru: lib/movie_list_screen.dart
isinya
import 'package:flutter/material.dart';
import 'movie_model.dart';
import 'movie_service.dart';
import 'movie_detail_screen.dart';
class MovieListScreen extends StatefulWidget {
const MovieListScreen({super.key});
@override
State<MovieListScreen> createState() =>
_MovieListScreenState();
}
class _MovieListScreenState
extends State<MovieListScreen> {
final MovieService _service = MovieService();
late Future<List<MovieModel>> _movieFuture;
@override
void initState() {
super.initState();
_movieFuture =
_service.fetchPopularMovies();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'🎬 Film Populer',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
body: FutureBuilder<List<MovieModel>>(
future: _movieFuture,
builder: (context, snapshot) {
// Loading
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
// Error
if (snapshot.hasError) {
return Center(
child: Text(
'Error: ${snapshot.error}',
),
);
}
// Data kosong
if (!snapshot.hasData ||
snapshot.data!.isEmpty) {
return const Center(
child: Text('Tidak ada film.'),
);
}
// Tampilkan list film
final movies = snapshot.data!;
return ListView.builder(
itemCount: movies.length,
itemBuilder: (context, index) {
final movie = movies[index];
return ListTile(
contentPadding:
const EdgeInsets.all(12),
leading: ClipRRect(
borderRadius:
BorderRadius.circular(8),
child: Image.network(
movie.posterUrl,
width: 50,
height: 75,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) =>
const Icon(
Icons.movie,
size: 50,
),
),
),
title: Text(
movie.title ??
'Tanpa Judul',
style: const TextStyle(
fontWeight:
FontWeight.bold,
),
),
subtitle: Text(
'⭐ ${movie.voteAverage?.toStringAsFixed(1)}',
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
MovieDetailScreen(
movie: movie,
),
),
);
},
);
},
);
},
),
);
}
}
FutureBuilder digunakan untuk menangani beberapa kondisi otomatis:
- loading saat request berjalan
- error saat request gagal
- data kosong
- data berhasil dimuat
Membuat Halaman Detail Film
Halaman ini digunakan untuk menampilkan detail lengkap film yang dipilih dari halaman list.
Buat file baru: lib/movie_detail_screen.dart
isinya:
import 'package:flutter/material.dart';
import 'movie_model.dart';
class MovieDetailScreen extends StatelessWidget {
final MovieModel movie;
const MovieDetailScreen({
super.key,
required this.movie,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
movie.title ?? 'Detail Film',
),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// Poster film
SizedBox(
width: double.infinity,
height: 300,
child: Image.network(
movie.posterUrl,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) =>
const Icon(
Icons.movie,
size: 80,
),
),
),
// Informasi film
Padding(
padding:
const EdgeInsets.all(16),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// Judul film
Text(
movie.title ?? '-',
style: const TextStyle(
fontSize: 22,
fontWeight:
FontWeight.bold,
),
),
const SizedBox(height: 8),
// Rating & tanggal rilis
Row(
children: [
const Icon(
Icons.star,
color: Colors.amber,
size: 18,
),
const SizedBox(width: 4),
Text(
movie.voteAverage
?.toStringAsFixed(1) ??
'-',
),
const SizedBox(width: 16),
const Icon(
Icons.calendar_today,
size: 16,
),
const SizedBox(width: 4),
Text(
movie.releaseDate ?? '-',
),
],
),
const Divider(height: 32),
// Label sinopsis
const Text(
'Sinopsis',
style: TextStyle(
fontSize: 16,
fontWeight:
FontWeight.bold,
),
),
const SizedBox(height: 8),
// Deskripsi film
Text(
movie.overview
?.isNotEmpty ==
true
? movie.overview!
: 'Tidak ada sinopsis tersedia.',
style: const TextStyle(
fontSize: 15,
height: 1.6,
),
),
],
),
),
],
),
),
);
}
}
Saat user menekan salah satu film di halaman list, objek MovieModel langsung dikirim ke MovieDetailScreen melalui konstruktor:
MovieDetailScreen(movie: movie)
Karena data sudah dikirim dari halaman sebelumnya, halaman detail tidak perlu melakukan request API lagi.
Flutter juga otomatis menambahkan tombol back pada AppBar, sehingga user bisa kembali ke halaman daftar film menggunakan Navigator.pop().
Membuat main.dart
File ini adalah entry point aplikasi Flutter. Tugasnya hanya menjalankan MaterialApp dan menampilkan MovieListScreen sebagai halaman utama.
Buka file lib/main.dart lalu ganti semua isinya menjadi:
import 'package:flutter/material.dart';
import 'movie_list_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Movie App',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
),
useMaterial3: true,
),
home: const MovieListScreen(),
);
}
}
Alur Keseluruhan Aplikasi
Saat aplikasi dibuka:
main()menjalankanMyAppMovieListScreentampil sebagai halaman utamainitState()memanggilfetchPopularMovies()- request API dikirim ke server TMDB
Selama request berjalan:
FutureBuildermenampilkan loading spinner
Ketika data berhasil diterima:
- JSON diparsing menjadi
List<MovieModel> ListView.buildermenampilkan daftar film
Saat user menekan salah satu film:
Navigator.push()membukaMovieDetailScreen- objek
MovieModeldikirim ke halaman detail
Saat tombol back ditekan:
- Flutter kembali ke halaman list sebelumnya
- data tetap tersimpan di memori tanpa request ulang ke API
Gambar Aplikasi



Kesimpulan
Pada pertemuan ini, kita telah belajar mengambil data dari REST API menggunakan Flutter, melakukan parsing JSON ke object Dart, menampilkan data dengan FutureBuilder, serta membuat navigasi antar halaman menggunakan data dari API. Dengan konsep ini, kalian sudah bisa mulai membuat aplikasi Flutter berbasis data realtime dari internet.
메타데이터
- post_id
- 1d9e8bbfb1b7
- slug
- menghubungkan-flutter-ke-http-rest-api-1d9e8bbfb1b7
- url
- https://medium.com/@dafafalah1616/menghubungkan-flutter-ke-http-rest-api-1d9e8bbfb1b7
- canonical_url
- https://medium.com/@dafafalah1616/menghubungkan-flutter-ke-http-rest-api-1d9e8bbfb1b7
- author_url
- https://medium.com/@dafafalah1616
- status
- ok
- fetched_at
- 2026-06-09 14:34:10