anynet 0.1.0-dev.1 copy "anynet: ^0.1.0-dev.1" to clipboard
anynet: ^0.1.0-dev.1 copied to clipboard

AnyNet is a Flutter networking layer (DEV) with get/post/put/delete helpers, retry, timeout, caching, offline support, logging, and unified error handling.

example/lib/main.dart

import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:anynet/anynet.dart';

void main() {
  runApp(const MyApp());
}

/// ─────────────────────────────────────────────────────────
/// AnyNet Mental Model
///
/// Think of AnyNet as:
///
/// UI
///  ↓
/// AnyNet.get/post/put/delete()   ← easy, http/dio-like API
///  ↓
/// AnyNetClient.send()            ← single execution pipeline
///  ↓
/// Interceptors (logging, auth)
///  ↓
/// Retry / Cache / Timeout
///  ↓
/// Network (IO / Dio adapter)
///
/// Beginners: just use AnyNet.get()
/// Advanced: customize AnyNetClient
/// ─────────────────────────────────────────────────────────

/// ---------------------------------------------------------------------------
/// Example Model
/// ---------------------------------------------------------------------------
class User {
  final int? id;
  final String name;
  final String email;

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

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int?,
      name: json['name'] ?? '',
      email: json['email'] ?? '',
    );
  }

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

  User copyWith({String? name, String? email}) {
    return User(id: id, name: name ?? this.name, email: email ?? this.email);
  }
}

/// ---------------------------------------------------------------------------
/// App
/// ---------------------------------------------------------------------------
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: AnyNetCrudExample(),
    );
  }
}

/// ---------------------------------------------------------------------------
/// Screen
/// ---------------------------------------------------------------------------
class AnyNetCrudExample extends StatefulWidget {
  const AnyNetCrudExample({super.key});

  @override
  State<AnyNetCrudExample> createState() => _AnyNetCrudExampleState();
}

class _AnyNetCrudExampleState extends State<AnyNetCrudExample> {
  late final AnyNet _anyNet;

  List<User> _users = [];
  bool _loading = false;
  String? _error;
  int _requestCount = 0;

  @override
  void initState() {
    super.initState();

    // 👉 Advanced configuration (safe to ignore for beginners)
    final client = AnyNetClient(
      baseUrl: 'https://jsonplaceholder.typicode.com',
      retryPolicy: const RetryPolicy(maxRetries: 2),
      cache: MemoryCache(),
      interceptors: [LoggingInterceptor()],
    );

    // 👉 Beginner-friendly API
    _anyNet = AnyNet(client);

    _fetchUsers();
  }

  /// -------------------------------------------------------------------------
  /// GET – Fetch users list
  ///
  /// http.get(url)
  /// dio.get('/users')
  /// ↓
  /// AnyNet.get('/users')
  /// -------------------------------------------------------------------------
  Future<void> _fetchUsers() async {
    _setLoading();

    final response = await _anyNet.get<List<User>>(
      '/users',
      cacheable: true,
      mapper: (json) => (json as List).map((e) => User.fromJson(e)).toList(),
    );

    _handleResponse(
      response,
      onSuccess: (data) {
        _users = data;
      },
    );
  }

  /// -------------------------------------------------------------------------
  /// POST – Add new user
  /// -------------------------------------------------------------------------
  Future<void> _addUser() async {
    _setLoading();

    final response = await _anyNet.post<User>(
      '/users',
      data: User(name: 'New User', email: 'new@anynet.dev').toJson(),
      mapper: (json) => User.fromJson(json),
    );

    _handleResponse(
      response,
      onSuccess: (user) {
        _users.insert(0, user);
      },
    );
  }

  /// -------------------------------------------------------------------------
  /// PUT – Update user
  /// -------------------------------------------------------------------------
  Future<void> _updateUser(User user) async {
    _setLoading();

    final updated = user.copyWith(name: '${user.name} ✨');

    final response = await _anyNet.put<User>(
      '/users/${user.id}',
      data: updated.toJson(),
      mapper: (_) => updated,
    );

    _handleResponse(
      response,
      onSuccess: (_) {
        final index = _users.indexWhere((u) => u.id == user.id);
        _users[index] = updated;
      },
    );
  }

  /// -------------------------------------------------------------------------
  /// DELETE – Remove user
  /// -------------------------------------------------------------------------
  Future<void> _deleteUser(User user) async {
    _setLoading();

    final response = await _anyNet.delete<void>(
      '/users/${user.id}',
      mapper: (_) => null,
    );

    _handleResponse(
      response,
      onSuccess: (_) {
        _users.removeWhere((u) => u.id == user.id);
      },
    );
  }

  /// -------------------------------------------------------------------------
  /// Unified response handler
  /// -------------------------------------------------------------------------
  void _handleResponse<T>(
    ApiResponse<T> response, {
    required void Function(T data) onSuccess,
  }) {
    setState(() {
      _loading = false;
      _requestCount++;
    });

    if (response.isSuccess && response.data != null) {
      onSuccess(response.data as T);
      _error = null;
    } else {
      log('[AnyNet] ERROR ${response.error?.message}');
      _error = _mapError(response.error);
    }
  }

  String _mapError(ApiError? error) {
    switch (error?.type) {
      case ApiErrorType.offline:
        return 'No internet connection';
      case ApiErrorType.timeout:
        return 'Request timed out';
      case ApiErrorType.network:
        return 'Network error';
      default:
        return 'Something went wrong';
    }
  }

  void _setLoading() {
    setState(() {
      _loading = true;
      _error = null;
    });
  }

  /// -------------------------------------------------------------------------
  /// UI
  /// -------------------------------------------------------------------------
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AnyNet Example'),
        actions: [
          IconButton(
            icon: const Icon(Icons.add),
            onPressed: _loading ? null : _addUser,
          ),
        ],
      ),
      body: Column(
        children: [
          if (_loading) const LinearProgressIndicator(),

          Padding(
            padding: const EdgeInsets.all(8),
            child: Text(
              _loading
                  ? 'Loading...'
                  : _error != null
                  ? 'Error occurred'
                  : 'Loaded ${_users.length} users • Requests: $_requestCount',
              style: Theme.of(context).textTheme.bodySmall,
            ),
          ),

          if (_error != null)
            Padding(
              padding: const EdgeInsets.all(12),
              child: Text(_error!, style: const TextStyle(color: Colors.red)),
            ),

          Expanded(
            child: ListView.builder(
              itemCount: _users.length,
              itemBuilder: (_, index) {
                final user = _users[index];
                return ListTile(
                  title: Text(user.name),
                  subtitle: Text(user.email),
                  trailing: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      IconButton(
                        icon: const Icon(Icons.edit),
                        onPressed: () => _updateUser(user),
                      ),
                      IconButton(
                        icon: const Icon(Icons.delete),
                        onPressed: () => _deleteUser(user),
                      ),
                    ],
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

/// ---------------------------------------------------------------------------
/// Features demonstrated:
/// ✔ Typed API responses
/// ✔ GET / POST / PUT / DELETE
/// ✔ http/dio-like API
/// ✔ Retry with backoff
/// ✔ Request caching
/// ✔ Interceptors (logging)
/// ✔ Unified error handling
/// ✔ Beginner + advanced friendly
/// ---------------------------------------------------------------------------
0
likes
150
points
42
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

AnyNet is a Flutter networking layer (DEV) with get/post/put/delete helpers, retry, timeout, caching, offline support, logging, and unified error handling.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on anynet