api_flow 2.0.0 copy "api_flow: ^2.0.0" to clipboard
api_flow: ^2.0.0 copied to clipboard

A comprehensive Flutter package for smart API management with Either pattern, local caching, and robust error handling

example/main.dart

import 'package:flutter/material.dart';
import 'package:api_flow/api_flow.dart';

// Example User model
class User {
  final int id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  factory User.fromJson(Map<String, dynamic> json) =>
      User(id: json['id'], name: json['name'], email: json['email']);

  Map<String, dynamic> toJson() => {'id': id, 'name': name, 'email': email};
}

void main() {
  runApp(ApiExample());
}
// Example API service
class ApiExample extends StatefulWidget {
  const ApiExample({super.key});

  @override
  State<ApiExample> createState() => _ApiExampleState();
}

class _ApiExampleState extends State<ApiExample> {
  List<User> users = [];
  bool isLoading = false;
  String statusMessage = '';

  @override
  void initState() {
    super.initState();
    _initializeApi();
    _loadUsers();
  }

  // Initialize the API service
  Future<void> _initializeApi() async {
    await EitherApiService.init(
      baseUrl: 'https://jsonplaceholder.typicode.com',
      enableCaching: true,
      boxNameCaching: 'api_cache',
      enableLogging: true,
    );
  }

  // Example: GET request with error handling
  Future<void> _loadUsers() async {
    setState(() {
      isLoading = true;
      statusMessage = 'Loading users...';
    });

    final result = await EitherApiService.get<List<User>>(
      endpoint: '/users',
      fromJson: (json) => (json as List).map((e) => User.fromJson(e)).toList(),
      enableCachingRequest: true,
    );

    // Handle the Either result
    result.fold(
      // Left side: Error occurred
      (error) {
        setState(() {
          isLoading = false;
          statusMessage = 'Error: ${error.message}';
        });

        // Handle different error types
        switch (error.type) {
          case ErrorType.noInternet:
            _showSnackbar('No internet connection');
            break;
          case ErrorType.timeout:
            _showSnackbar('Request timeout - please try again');
            break;
          case ErrorType.serverError:
            _showSnackbar('Server error - please try later');
            break;
          default:
            _showSnackbar('Something went wrong');
        }
      },
      // Right side: Success
      (success) {
        setState(() {
          users = success.dataFromApi ?? [];
          isLoading = false;
          statusMessage = 'Loaded ${users.length} users';
        });

        // Access additional response details
        debugPrint('Response time: ${success.dioDetails.calculatedDuration}ms');
        debugPrint('Status code: ${success.dioDetails.statusCode}');
      },
    );
  }

  // Example: POST request - Create new user
  Future<void> _createUser(String name, String email) async {
    setState(() {
      statusMessage = 'Creating user...';
    });

    final newUser = User(id: 0, name: name, email: email);

    final result = await EitherApiService.post<User>(
      endpoint: '/users',
      data: newUser.toJson(),
      fromJson: (json) => User.fromJson(json),
      invalidateListCache: true, // Clear users list cache
    );

    result.fold(
      (error) {
        setState(() {
          statusMessage = 'Failed to create user: ${error.message}';
        });
        _showSnackbar('Failed to create user');
      },
      (success) {
        final createdUser = success.dataFromApi!;
        setState(() {
          users.insert(0, createdUser);
          statusMessage = 'User ${createdUser.name} created successfully';
        });
        _showSnackbar('User created successfully');
      },
    );
  }

  // Example: PUT request - Update user
  Future<void> _updateUser(User user, String newName) async {
    final updatedUser = User(id: user.id, name: newName, email: user.email);

    final result = await EitherApiService.put<User>(
      endpoint: '/users/${user.id}',
      data: updatedUser.toJson(),
      fromJson: (json) => User.fromJson(json),
      updateCache: true, // Update cache with new data
    );

    result.fold((error) => _showSnackbar('Failed to update user'), (success) {
      setState(() {
        final index = users.indexWhere((u) => u.id == user.id);
        if (index != -1) {
          users[index] = success.dataFromApi!;
        }
        statusMessage = 'User updated successfully';
      });
      _showSnackbar('User updated');
    });
  }

  // Example: DELETE request - Remove user
  Future<void> _deleteUser(User user) async {
    final result = await EitherApiService.delete<void>(
      endpoint: '/users/${user.id}',
      invalidateCache: true, // Remove from cache
    );

    result.fold((error) => _showSnackbar('Failed to delete user'), (success) {
      setState(() {
        users.removeWhere((u) => u.id == user.id);
        statusMessage = 'User deleted successfully';
      });
      _showSnackbar('User deleted');
    });
  }

  // Helper method to show snackbar
  void _showSnackbar(String message) {
    ScaffoldMessenger.of(
      context,
    ).showSnackBar(SnackBar(content: Text(message)));
  }

  // UI to create new user
  void _showCreateUserDialog() {
    final nameController = TextEditingController();
    final emailController = TextEditingController();

    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Create New User'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextField(
              controller: nameController,
              decoration: InputDecoration(labelText: 'Name'),
            ),
            TextField(
              controller: emailController,
              decoration: InputDecoration(labelText: 'Email'),
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.of(context).pop();
              _createUser(nameController.text, emailController.text);
            },
            child: Text('Create'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('EitherApiService Example'),
        actions: [IconButton(icon: Icon(Icons.refresh), onPressed: _loadUsers)],
      ),
      body: Column(
        children: [
          // Status message
          Container(
            width: double.infinity,
            padding: EdgeInsets.all(16),
            color: Colors.grey[100],
            child: Text(
              statusMessage,
              style: TextStyle(
                fontWeight: FontWeight.w500,
                color: statusMessage.contains('Error')
                    ? Colors.red
                    : Colors.black,
              ),
            ),
          ),

          // Loading indicator
          if (isLoading) LinearProgressIndicator(),

          // Users list
          Expanded(
            child: users.isEmpty
                ? Center(
                    child: isLoading
                        ? CircularProgressIndicator()
                        : Text('No users found'),
                  )
                : ListView.builder(
                    itemCount: users.length,
                    itemBuilder: (context, index) {
                      final user = users[index];
                      return ListTile(
                        leading: CircleAvatar(child: Text(user.name[0])),
                        title: Text(user.name),
                        subtitle: Text(user.email),
                        trailing: PopupMenuButton(
                          itemBuilder: (context) => [
                            PopupMenuItem(value: 'edit', child: Text('Edit')),
                            PopupMenuItem(
                              value: 'delete',
                              child: Text('Delete'),
                            ),
                          ],
                          onSelected: (value) {
                            if (value == 'edit') {
                              _showEditUserDialog(user);
                            } else if (value == 'delete') {
                              _showDeleteConfirmation(user);
                            }
                          },
                        ),
                      );
                    },
                  ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _showCreateUserDialog,
        tooltip: 'Add User',
        child: Icon(Icons.add),
      ),
    );
  }

  void _showEditUserDialog(User user) {
    final nameController = TextEditingController(text: user.name);

    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Edit User'),
        content: TextField(
          controller: nameController,
          decoration: InputDecoration(labelText: 'Name'),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.of(context).pop();
              _updateUser(user, nameController.text);
            },
            child: Text('Update'),
          ),
        ],
      ),
    );
  }

  void _showDeleteConfirmation(User user) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Delete User'),
        content: Text('Are you sure you want to delete ${user.name}?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.of(context).pop();
              _deleteUser(user);
            },
            style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
            child: Text('Delete'),
          ),
        ],
      ),
    );
  }
}
2
likes
160
points
51
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter package for smart API management with Either pattern, local caching, and robust error handling

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

crypto, dartz, dio, flutter, hive, hive_flutter

More

Packages that depend on api_flow