networking_layer 1.0.0
networking_layer: ^1.0.0 copied to clipboard
A robust, solid-compliant networking layer using Dio.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:dartz/dartz.dart' hide State;
import 'package:networking_layer/networking_layer.dart';
// -----------------------------------------------------------------------------
// 1. Data Models
// -----------------------------------------------------------------------------
class User {
final int id;
final String name;
final String? email;
User({required this.id, required this.name, this.email});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] is int
? json['id']
: int.tryParse(json['id'].toString()) ?? 0,
name: json['name'] ?? '',
email: json['email'],
);
}
Map<String, dynamic> toJson() => {'name': name, 'email': email};
}
// -----------------------------------------------------------------------------
// 2. Repository with ApiClient Mixin
// -----------------------------------------------------------------------------
class UserRepository with ApiClient {
// ----------------- REST EXAMPLES -----------------
/// [REST] GET Request
Future<Either<HelperResponse, User>> getUserREST(String id) async {
return await get<User>(
'/users/$id',
fromJson: (json) => User.fromJson(json),
);
}
/// [REST] POST Request (Create User)
Future<Either<HelperResponse, User>> createUserREST(User user) async {
return await post<User>(
'/users',
data: user.toJson(),
fromJson: (json) => User.fromJson(json),
);
}
// ----------------- GRAPHQL EXAMPLES -----------------
/// [GraphQL] Query Example
/// Note: JSONPlaceholder doesn't support GraphQL, so this URL will likely fail
/// with 404 if run against it, but the code structure is correct.
Future<Either<HelperResponse, User>> getUserGraphQL(String id) async {
const String query = r'''
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
''';
return await graphQLQuery<User>(
query,
variables: {'id': id},
dataKey: 'user', // content inside data: { user: { ... } }
fromJson: (json) => User.fromJson(json),
);
}
/// [GraphQL] Mutation Example
Future<Either<HelperResponse, User>> updateUserGraphQL(User user) async {
const String mutation = r'''
mutation UpdateUser($input: UserInput!) {
updateUser(input: $input) {
id
name
email
}
}
''';
return await graphQLMutation<User>(
mutation,
variables: {'input': user.toJson()},
dataKey: 'updateUser',
fromJson: (json) => User.fromJson(json),
);
}
}
// -----------------------------------------------------------------------------
// 3. UI Implementation
// -----------------------------------------------------------------------------
void main() {
// Define translation function
String translate(String key) {
const translations = {
'no_internet_connection': 'No Internet Connection',
'something_went_wrong_please_try_again': 'Something went wrong',
};
return translations[key] ?? key;
}
// Initialize DioServices
DioServices.instance.init(
DioConfig(
baseUrl: 'https://jsonplaceholder.typicode.com',
getToken: () => 'dummy_token',
translate: translate,
onTokenExpired: () => debugPrint('Token expired!'),
onConnectionError: () => debugPrint('Connection error!'),
),
);
runApp(const MaterialApp(home: NetworkingExamplePage()));
}
class NetworkingExamplePage extends StatefulWidget {
const NetworkingExamplePage({super.key});
@override
State<NetworkingExamplePage> createState() => _NetworkingExamplePageState();
}
class _NetworkingExamplePageState extends State<NetworkingExamplePage> {
final UserRepository _repository = UserRepository();
String _log = 'Ready to test...';
bool _isLoading = false;
void _clearLog() => setState(() => _log = 'Ready to test...');
void _logger(String message) {
setState(() => _log = '$message\n\n$_log');
}
Future<void> _runTest(
String name,
Future<Either<HelperResponse, dynamic>> Function() action,
) async {
setState(() => _isLoading = true);
_logger('--- Testing $name ---');
final result = await action();
result.fold(
(error) => _logger('❌ Error: [${error.statusCode}] ${error.message}'),
(data) {
if (data is User) {
_logger('✅ Success: User(id: ${data.id}, name: ${data.name})');
} else {
_logger('✅ Success: $data');
}
},
);
setState(() => _isLoading = false);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('REST & GraphQL Example')),
body: Column(
children: [
Expanded(
flex: 2,
child: Container(
width: double.infinity,
color: Colors.black87,
padding: const EdgeInsets.all(16),
child: SingleChildScrollView(
child: Text(
_log,
style: const TextStyle(
color: Colors.greenAccent,
fontFamily: 'Courier',
),
),
),
),
),
if (_isLoading) const LinearProgressIndicator(),
Expanded(
flex: 3,
child: ListView(
padding: const EdgeInsets.all(16),
children: [
const Text(
'REST API Tests',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(height: 10),
ElevatedButton.icon(
onPressed: () => _runTest(
'REST GET User (ID: 1)',
() => _repository.getUserREST('1'),
),
icon: const Icon(Icons.download),
label: const Text('GET Request (Fetch User)'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade100,
),
),
const SizedBox(height: 10),
ElevatedButton.icon(
onPressed: () => _runTest(
'REST POST User',
() => _repository.createUserREST(
User(id: 0, name: 'New User', email: 'test@example.com'),
),
),
icon: const Icon(Icons.upload),
label: const Text('POST Request (Create User)'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green.shade100,
),
),
const Divider(height: 40),
const Text(
'GraphQL Tests',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
const Text(
'(Note: These will fail on JSONPlaceholder)',
style: TextStyle(color: Colors.grey, fontSize: 12),
),
const SizedBox(height: 10),
ElevatedButton.icon(
onPressed: () => _runTest(
'GraphQL Query',
() => _repository.getUserGraphQL('1'),
),
icon: const Icon(Icons.search),
label: const Text('GraphQL Query (Fetch User)'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple.shade100,
),
),
const SizedBox(height: 10),
ElevatedButton.icon(
onPressed: () => _runTest(
'GraphQL Mutation',
() => _repository.updateUserGraphQL(
User(id: 1, name: 'Updated Name'),
),
),
icon: const Icon(Icons.edit),
label: const Text('GraphQL Mutation (Update User)'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange.shade100,
),
),
],
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _clearLog,
child: const Icon(Icons.cleaning_services),
),
);
}
}