Flux API Client
A Flutter package for handling HTTP requests easily and efficiently with dynamic response mapping.
Features
- Supports GET, POST, PUT, and DELETE HTTP requests.
- Simple JSON serialization and deserialization.
- Customizable error handling with logging options.
- Easy integration with Flutter applications.
Getting Started
Creating a Model Class
Define a model class that represents the data you expect from the API. For example, for a Product
entity:
class Product {
final int? id;
final String name;
final String username;
Product({this.id, required this.name, required this.username});
factory Product.fromJson(Map<String, dynamic> json) {
return Product(
id: json['id'],
name: json['name'],
username: json['username'],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'username': username,
};
}
}
ProductsPage
The ProductsPage
is a simple UI for displaying a list of products, creating new products, and deleting existing ones.
class ProductsPage extends StatefulWidget {
@override
_ProductsPageState createState() => _ProductsPageState();
}
class _ProductsPageState extends State<ProductsPage> {
late Future<List<Product>?> futureProducts;
final String url = 'https://jsonplaceholder.typicode.com/users';
@override
void initState() {
super.initState();
futureProducts = fetchProducts();
}
Future<List<Product>?> fetchProducts() async {
final getRequest = GetRequest<Product>(
url: url,
fromJson: (json) => Product.fromJson(json),
);
return await getRequest.fetchProducts();
}
Future<void> createProduct() async {
final newProduct = Product(id: null, name: "shiboo", username: "sarvajeet");
final postRequest = PostRequest<Product>(
url: url,
fromJson: (json) => Product.fromJson(json),
body: newProduct.toJson(),
);
final response = await postRequest.send();
if (response != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Product Created: ${response.name}')),
);
setState(() {
futureProducts = fetchProducts();
});
}
}
Future<void> deleteProduct(int id) async {
final deleteRequest = DeleteRequest<Product>(
url: '$url/$id',
fromJson: (json) => Product.fromJson(json),
shouldPrintErrors: true,
shouldPrintStackTrace: true,
);
final isDeleted = await deleteRequest.delete();
if (isDeleted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Product Deleted Successfully.')),
);
setState(() {
futureProducts = fetchProducts();
});
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Error deleting product.')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Products')),
body: FutureBuilder<List<Product>?>(
future: futureProducts,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (snapshot.data == null || snapshot.data!.isEmpty) {
return const Center(child: Text('No products found.'));
} else {
final products = snapshot.data!;
return ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ListTile(
title: Text(product.name),
subtitle: Text(product.username),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () => deleteProduct(product.id!),
),
);
},
);
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: createProduct,
tooltip: 'Create Product',
child: const Icon(Icons.add),
),
);
}
}
ClientService with GetX Example
The ClientService
class simplifies HTTP interactions for fetching, creating, and deleting products.
ClientService.dart
class ClientService {
final String baseUrl = 'https://jsonplaceholder.typicode.com';
final String usersEndpoint = '/users';
Future<List<Product>?> fetchProducts() async {
try {
final getRequest = GetRequest<Product>(
responsePrint: true,
url: '$baseUrl$usersEndpoint',
fromJson: (json) => Product.fromJson(json),
);
return await getRequest.fetchProducts();
} catch (e) {
return null;
}
}
Future<Product?> createProduct(Product product) async {
try {
final postRequest = PostRequest<Product>(
url: '$baseUrl$usersEndpoint',
fromJson: (json) => Product.fromJson(json),
body: product.toJson(),
);
return await postRequest.send();
} catch (e) {
return null;
}
}
Future<bool> deleteProduct(int id) async {
try {
final deleteRequest = DeleteRequest<Product>(
url: '$baseUrl$usersEndpoint/$id',
fromJson: (json) => Product.fromJson(json),
shouldPrintErrors: true,
shouldPrintStackTrace: true,
);
return await deleteRequest.delete();
} catch (e) {
return false;
}
}
}
ProductsController
The ProductsController
uses GetX
to manage the state and interact with the ClientService
.
class ProductsController extends GetxController {
final ClientService productService = ClientService();
var products = <Product>[].obs;
var isLoading = true.obs;
@override
void onInit() {
super.onInit();
fetchProducts();
}
Future<void> fetchProducts() async {
_setLoading(true);
try {
final fetchedProducts = await productService.fetchProducts();
products.value = fetchedProducts ?? [];
} catch (e) {
_showSnackbar('Error', 'Failed to fetch products.');
} finally {
_setLoading(false);
}
}
Future<void> createProduct() async {
final newProduct = Product(id: null, name: "shiboo", username: "sarvajeet");
try {
final response = await productService.createProduct(newProduct);
if (response != null) {
products.add(response);
_showSnackbar('Success', 'Product Created: ${response.name}');
}
} catch (e) {
_showSnackbar('Error', 'Failed to create product.');
}
}
Future<void> deleteProduct(int id) async {
try {
final isDeleted = await productService.deleteProduct(id);
if (isDeleted) {
products.removeWhere((product) => product.id == id);
_showSnackbar('Success', 'Product Deleted Successfully.');
} else {
_showSnackbar('Error', 'Error deleting product.');
}
} catch (e) {
_showSnackbar('Error', 'Failed to delete product.');
}
}
void _setLoading(bool loading) {
isLoading.value = loading;
}
void _showSnackbar(String title, String message) {
Get.snackbar(title, message);
}
}