Membangun aplikasi web di era modern memerlukan pondasi yang kokoh. Framework modern memberikan fleksibilitas luar biasa bagi developer untuk menghadirkan fitur kompleks secara cepat tanpa mengabaikan aspek keamanan dan keandalan sistem.
Tahapan Implementasi & Walkthrough Kode
Berikut adalah langkah demi langkah teknis yang dapat Anda ikuti langsung pada codebase Anda:
Tahap 1: Penulisan Kode & Konfigurasi
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:todo_list_supabase/model/todo_model.dart';
class TodoService {
final _client = Supabase.instance.client;
Future<List<TodoModel>> fetchTodos() async {
return run(() async {
final response = await _client
.from('todos')
.select()
.order('created_at', ascending: false);
return TodoModel.fromJsonToList(response);
});
}
Future<void> addTodo(String title) async {
return run(() async {
await _client.from('todos').insert({
'title': title,
'is_done': false,
'created_at': DateTime.now().toIso8601String(),
});
});
}
Future<void> toggleDone(String id, bool isDone) async {
return run(() async {
await _client.from('todos').update({'is_done': !isDone}).eq('id', id);
});
}
Future<void> deleteTodo(String id) async {
return run(() async {
await _client.from('todos').delete().eq('id', id);
});
}
Future<T> run<T>(Future<T> Function() function) async {
try {
return await function();
} on PostgrestException catch (error) {
throw ServerException(message: error.message);
} catch (error) {
throw ServerException(message: error.toString());
}
}
}
class ServerException implements Exception {
final String message;
ServerException({this.message = 'Server error'});
}
Tahap 2: Penulisan Kode & Konfigurasi
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:todo_list_supabase/model/todo_model.dart';
import 'package:todo_list_supabase/service/todo_service.dart';
Tahap 3: Penulisan Kode & Konfigurasi
class TodoCubit extends Cubit<List<TodoModel>> {
final TodoService _service;
TodoCubit(super.initialState, this._service);
Tahap 4: Penulisan Kode & Konfigurasi
Future<void> fetchTodos() async {
try {
final todos = await _service.fetchTodos();
emit(todos);
} catch (e) {
emit(state); // Tetap gunakan state lama jika error
rethrow;
}
}
Tahap 5: Penulisan Kode & Konfigurasi
Future<void> addTodo(String title) async {
try {
await _service.addTodo(title);
await fetchTodos(); // Refresh daftar setelah menambah
} catch (e) {
emit(state);
rethrow;
}
}
Tahap 6: Penulisan Kode & Konfigurasi
Future<void> toggleDone(TodoModel todo) async {
try {
await _service.toggleDone(todo.id, todo.isDone);
await fetchTodos(); // Refresh daftar setelah update
} catch (e) {
emit(state);
rethrow;
}
}
Tahap 7: Penulisan Kode & Konfigurasi
Future<void> deleteTodo(String id) async {
try {
await _service.deleteTodo(id);
await fetchTodos(); // Refresh daftar setelah delete
} catch (e) {
emit(state);
rethrow;
}
}
Selalu gunakan pendekatan deklaratif, validasi input seawal mungkin di boundary layer, dan lakukan logging terstruktur untuk memudahkan observability ketika sistem dijalankan di lingkungan cloud produksi.
Kesimpulan
Dengan mengikuti langkah-langkah terstruktur di atas, implementasi modul Anda akan jauh lebih rapi, aman dari bug umum, serta siap diskalakan ke lingkungan produksi.
Nantikan artikel tutorial praktis lainnya seputar fullstack development, microservices, dan otomasi AI di Blog Engineering SiHubung. Selamat mencoba!