CRUD Public API
Untuk implementasinya, akan menggunakan package http. Sebetulnya ada package lain, namun disini akan mengikuti dari package official flutter yaitu http. http | Dart Package (pub.dev).
Sumber public API yang akan digunakan:
JSONPlaceholder - Free Fake REST API (typicode.com)
Panduan cara akses API jsonplaceholder tersebut:
JSONPlaceholder - Guide (typicode.com)
Sebelum mulai, tambahkan dulu package http di dependencies dan package DMethod untuk keperluan tracking dan check response. Dan package DInput untuk concise input.
1. GET
Untuk request dibuat didalam fungsi getPosts kemudian dipanggil/dieksekusi dibagian initState. Endpoint/url di parsing ke bentu Uri kemudian dimasukkan ke input param http dengan method get. Karena http.get bertipe Future, maka salah satu cara untuk akses data yang direturn bisa menggunakan .then. Cek response data menggunakan package DMethod dan akan Nampak pada bagian console.
Extrak data response body dari awalnya json yaitu bentuk data yang enkripsi kebentuk string. Bentuk root utama body nya adalah List, sehingga setelah di ekstrak langsung dimasukkan ke variable List. Kemudian auto casting menggunakan List.from dan dimasukkan ke variable global scope class yang Bernama posts. posts ini digunakan di view body screen/scaffold. Biar UI nya diupdate setelah selesai ambil data dari response, panggil setState.
import 'dart:convert';
import 'package:fd_log/fd_log.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
List<Map> posts = [];
getPosts() {
String url = 'https://jsonplaceholder.typicode.com/posts';
http.get(Uri.parse(url)).then((response) {
FDLog(useDebug: true).response(response);
List list = jsonDecode(response.body);
posts = List.from(list);
setState(() {});
});
}
void initState() {
getPosts();
super.initState();
}
ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
Map item = posts[index];
return ListTile(
leading: CircleAvatar(
child: Text('${index + 1}'),
),
title: Text(
item['title'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: Text(
item['body'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
);
},
),
2. POST
Pertama buat objek input terlebih dahulu.
final edtTitle = TextEditingController();
final edtBody = TextEditingController();
Kemudian pasangkan di widget.
DInput(controller: edtTitle),
const SizedBox(height: 16),
DInput(controller: edtBody),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
createPost(edtTitle.text, edtBody.text, 1);
},
child: const Text('Add Post'),
),
Untuk request dibuat didalam fungsi craetePost kemudian dipanggil/dieksekusi dibagian Ketika button di klik. Method yang digunakan adalah POST, karena tujuannya untuk input data baru dan kirim data lewat request body. Semua data di request body harus bertipe string semua. Title dan body diambil dari input yang diedit, sedangkan userId langsung aja karena ini test.
createPost(String title, String body, int userId) async {
String url = 'https://jsonplaceholder.typicode.com/posts';
try {
final response = await http.post(
Uri.parse(url),
body: {
'title': title,
'body': body,
'userId': userId.toString(),
},
);
FDLog(useDebug: true).response(response);
} catch (e) {
FDLog(useDebug: true).title('createPost-error', e.toString());
}
}
3. PUT
Step nya sama seperti POST, namun ada beberapa perbedaan sebagai berikut.
- Kita lakukan inisialisasi nilai awal input bahwa terdapat old value.
- Pada bagian url, ada tambahan data yaitu postId sebagai index data mana yang mau diupdate.
- postId ditambahkan juga ke request body, semua field mesti ada datanya karena menggunakan method PUT yang mengupdate seluruh field. Artinya jika value old field sama dengan value new field maka akan di replace dengan data yang sama (tetap diupdate).
final edtTitle = TextEditingController();
final edtBody = TextEditingController();
// init
edtTitle.text = 'foo';
edtBody.text = 'bar';
DInput(controller: edtTitle),
const SizedBox(height: 16),
DInput(controller: edtBody),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
updatePost(1, edtTitle.text, edtBody.text, 1);
},
child: const Text('Update Post'),
),
updatePost(int postId, String newTitle, String newBody, int userId) {
String url = 'https://jsonplaceholder.typicode.com/posts/$postId';
http.put(
Uri.parse(url),
body: {
'id': postId.toString(),
'title': newTitle,
'body': newBody,
'userId': userId.toString(),
},
).then((response) {
FDLog(useDebug: true).response(response);
});
}
![]() | ![]() |
4. PATCH
Step nya sama seperti PUT namun ada perbedaan, pada bagian request body, hanya memasukkan data field yang ingin diupdate saja (sebagian).
final edtTitle = TextEditingController();
// init
edtTitle.text = 'foo';
DInput(controller: edtTitle),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
updatePost(1, edtTitle.text);
},
child: const Text('Update Post'),
),
updatePost(int postId, String newTitle) async {
try {
String url = 'https://jsonplaceholder.typicode.com/posts/$postId';
final response = await http.patch(
Uri.parse(url),
body: {
'title': newTitle,
},
);
FDLog(useDebug: true).response(response);
if (response.statusCode == 200) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Success Update')),
);
}
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed Update')),
);
}
}
} catch (e) {
FDLog(useDebug: true).title('exception', e.toString());
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed Update')),
);
}
}
}
5. DELETE
Bisa sama seperti PUT atau GET. Namun biasanya tanpa ada request body. Untuk kondisi data yang ingin dihapus, dikirim melalui url. Untuk response delete biasa tanpa data. Only use check status code sebagai tanda berhasil/gagal delete.
int postId = 1;
String url = 'https://jsonplaceholder.typicode.com/posts/$postId';
http.delete(Uri.parse(url)).then((response) {
FDLog().response(response);
});