gtd_network 1.0.5 copy "gtd_network: ^1.0.5" to clipboard
gtd_network: ^1.0.5 copied to clipboard

Network helper for request CRUD.

VNLook Network Package #

A Flutter package for simplified API communication using Dio HTTP client.

Features #

  • Easy API request configuration
  • Built-in environment management
  • Support for various HTTP methods
  • File upload capabilities
  • Progress tracking
  • Structured error handling

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  gtd_network: ^1.0.5

Usage #

Basic Setup #

  1. Create an environment for your API:
final environment = BaseEnvironment(
  baseUrl: 'api.example.com',  // Base URL without protocol
  platformPath: 'api/v1',      // Path prefix for all endpoints
  headers: {                   // Default headers
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
);
  1. Create an endpoint for your request:
final endpoint = GtdEndpoint(
  env: environment,
  path: 'users',  // This will be appended to the platformPath
);
  1. Configure a network request:
final networkService = GtdNetworkService.shared;
networkService.request = GTDNetworkRequest(
  type: GtdMethod.get,       // HTTP method
  enpoint: endpoint,
  queryParams: {             // Optional query parameters
    'page': 1,
    'limit': 10,
  },
  data: {                    // Optional request body for POST/PUT
    'name': 'John Doe',
    'email': 'john@example.com',
  },
);
  1. Execute the request:
try {
  final response = await networkService.execute();
  print('Status code: ${response.statusCode}');
  print('Response data: ${response.data}');
} on DioException catch (e) {
  print('Request failed: ${e.message}');
}

Example: GET Request #

// Create environment and endpoint
final environment = BaseEnvironment(
  baseUrl: 'jsonplaceholder.typicode.com',
  platformPath: '',
  headers: {'Accept': 'application/json'},
);
final endpoint = GtdEndpoint(env: environment, path: 'posts');

// Configure request
final networkService = GtdNetworkService.shared;
networkService.request = GTDNetworkRequest(
  type: GtdMethod.get,
  enpoint: endpoint,
  queryParams: {'userId': 1},
);

// Execute
try {
  final response = await networkService.execute();
  print('GET request successful: ${response.statusCode}');
  print('Data: ${response.data}');
} catch (e) {
  final gtdError = e as GtdError;
  print('GET request failed: ${gtdError.message}');
}

Example: GET Request with Path Parameters #

// Create environment and endpoint
final environment = BaseEnvironment(
  baseUrl: 'jsonplaceholder.typicode.com',
  platformPath: '',
  headers: {'Accept': 'application/json'},
);

// Getting a specific post by ID
final postId = 1;
final endpoint = GtdEndpoint(env: environment, path: 'posts/$postId');

// Configure request
final networkService = GtdNetworkService.shared;
networkService.request = GTDNetworkRequest(
  type: GtdMethod.get,
  enpoint: endpoint,
);

// Execute
try {
  final response = await networkService.execute();
  print('GET request successful: ${response.statusCode}');
  print('Post data: ${response.data}');
  // Access specific fields
  print('Title: ${response.data['title']}');
  print('Body: ${response.data['body']}');
} catch (e) {
  final gtdError = e as GtdError;
  print('GET request failed: ${gtdError.message}');
}

Example: File Upload #

// Create a file to upload
final file = File('path/to/your/file.jpg');

// Configure environment and endpoint
final environment = BaseEnvironment(
  baseUrl: 'api.example.com',
  platformPath: 'api/v1',
  headers: {'Accept': 'application/json'},
);
final endpoint = GtdEndpoint(env: environment, path: 'upload');

// Configure request
final networkService = GtdNetworkService.shared;
networkService.request = GTDNetworkRequest(
  type: GtdMethod.post,
  enpoint: endpoint,
  data: {'description': 'Profile picture'},
);

// Upload file
try {
  final response = await networkService.uploadFile(
    file: file,
    fieldName: 'image',
    onSendProgress: (int sent, int total) {
      final progress = (sent / total * 100).toStringAsFixed(2);
      print('Upload progress: $progress%');
    },
  );
  print('Upload successful: ${response.statusCode}');
  print('Response: ${response.data}');
} catch (e) {
  final gtdError = e as GtdError;
  print('Upload failed: ${gtdError.message}');
}

Advanced Usage #

Authentication #

// Add authentication token to all requests
environment.headers['Authorization'] = 'Bearer YOUR_TOKEN_HERE';

Customizing Timeout #

// Customize timeout settings
networkService.connectTimeout = const Duration(seconds: 10);
networkService.receiveTimeout = const Duration(seconds: 30);

Using a Mock API for Testing #

final testEnvironment = BaseEnvironment(
  baseUrl: 'localhost:8080',  // Point to your mock server
  platformPath: 'mock/api',
  headers: {'Accept': 'application/json'},
);

Standardized Error Handling #

The package provides a standardized way to handle errors with the GtdError class. All network service methods will only throw GtdError exceptions, making error handling consistent across the application:

try {
  final response = await networkService.execute();
  return response.data;
} catch (e) {
  // All exceptions from networkService are GtdError
  final gtdError = e as GtdError;
  
  // You can access additional properties
  print('Status code: ${gtdError.statusCode}');
  print('Error message: ${gtdError.message}');
  print('Stack trace: ${gtdError.stackTrace}');
  
  // You can check for specific errors
  if (gtdError.statusCode == 401) {
    // Handle authentication errors
  } else if (gtdError.errorCode == 'NETWORK_ERROR') {
    // Handle network connectivity issues
  }
  
  // Rethrow or handle the error
  throw gtdError;
}

Error Properties

The GtdError class provides these properties:

  • message: Human-readable error message
  • statusCode: HTTP status code if available
  • errorCode: Custom error code for categorization
  • originalError: Original error that caused this exception, which can be another GtdError
  • stackTrace: Full stack trace for debugging

Error Factory Methods

// Create from DioException (used internally)
final error1 = GtdError.fromDioError(dioException);

// Create from any exception
final error2 = GtdError.fromException(exception, stackTrace);

// Create with custom message
final error3 = GtdError.custom(
  'Custom error message',
  statusCode: 400,
  errorCode: 'VALIDATION_FAILED',
);

// Create from another GtdError
final error4 = GtdError.fromError(
  existingError,
  message: 'More specific error message',
  errorCode: 'SPECIFIC_ERROR_CODE',
);

Getting the Root Error

You can use the getOriginalErrorSource() method to get the root cause of errors:

final rootCause = gtdError.getOriginalErrorSource();
print('Root cause: $rootCause');

Detailed Logging

For debugging, you can get a detailed error report:

final error = GtdError.fromDioError(dioException);
print(error.toDetailedString());

This will output:

GtdError: Resource not found (404) [code: 404]
Original error: DioException [...]
Stack trace:
#0 ...

Creating Resource Modules #

You can organize your API calls into dedicated resource modules following this structure:

user_resource/
├── api/
│   └── user_resource_api.dart
├── models/
│   ├── request/
│   │   └── gtd_user_profile_rq.dart
│   └── response/
│       ├── gtd_user_detail_rs.dart
│       └── gtd_user_list_rs.dart
├── gtd_user_endpoint.dart
└── user_resource.dart
  1. Create endpoints in a dedicated class:
// gtd_user_endpoint.dart
class GtdUserEndpoint extends GtdEndpoint {
  GtdUserEndpoint({required super.env, required super.path});
  
  // Define API paths as constants
  static const String kGetUserDetail = '/api/users/profile';
  static const String kGetUserList = '/api/users/list';

  // Create factory methods for each endpoint
  static GtdEndpoint getUserDetail(GTDEnvType envType, String userId) {
    const path = kGetUserDetail;
    return GtdEndpoint(env: GtdEnvironment(env: envType), path: "$path/$userId");
  }

  static GtdEndpoint getUserList(GTDEnvType envType) {
    const path = kGetUserList;
    return GtdEndpoint(env: GtdEnvironment(env: envType), path: path);
  }
}
  1. Create request/response models:
// models/request/gtd_user_profile_rq.dart
class GtdUserProfileRq {
  String userId;
  bool includeSettings;
  bool includePreferences;
  
  // Constructor, toMap(), fromMap(), etc.
  
  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'userId': userId,
      'includeSettings': includeSettings,
      // Other properties...
    };
  }
}
  1. Implement the API client:
// api/user_resource_api.dart
class UserResourceApi {
  GtdNetworkService networkService = GtdNetworkService.shared;
  GTDEnvType envType = AppConst.shared.envType;

  UserResourceApi._();
  static final shared = UserResourceApi._();

  Future<GtdUserDetail> getUserDetailById(String userId) async {
    try {
      final networkRequest = GTDNetworkRequest(
          type: GtdMethod.get, 
          enpoint: GtdUserEndpoint.getUserDetail(envType, userId)
      );
      networkService.request = networkRequest;
      final response = await networkService.execute();
      GtdUserDetailRs userDetailRs = JsonParser.jsonToModel(
        GtdUserDetailRs.fromJson, 
        response.data
      );
      
      if ((userDetailRs.errors ?? []).isNotEmpty) {
        throw GtdApiError.fromErrorConstant(GtdErrorConstant.unknown);
      }
      return userDetailRs.result ?? GtdUserDetail();
    } catch (e) {
      // All errors from networkService are GtdError
      throw e;
    }
  }
  
  // Other API methods...
}
  1. Create an export file:
// user_resource.dart
export 'api/user_resource_api.dart';
export 'gtd_user_endpoint.dart';
export 'models/response/gtd_user_detail_rs.dart';

Example: Using a Resource Module #

// Import the resource module
import 'package:your_package/network/user_resource/user_resource.dart';

// Usage in your application
Future<void> fetchUserDetails() async {
  try {
    // Use the API client
    final userApi = UserResourceApi.shared;
    final userId = "user123";
    
    // Call the API method
    final userDetail = await userApi.getUserDetailById(userId);
    
    // Process the results
    print('User name: ${userDetail.fullName}');
    print('Email: ${userDetail.email}');
    // Process other properties...
  } catch (e) {
    print('Error fetching user details: $e');
  }
}

// Example with request model
Future<void> searchUsers() async {
  try {
    // Create the request model
    final request = GtdUserSearchRq(
      searchTerm: "john",
      pageSize: 20,
      pageNumber: 1,
      includeSuspended: false,
    );
    
    // Call the API with the request model
    final userApi = UserResourceApi.shared;
    final users = await userApi.searchUsers(request);
    
    // Process the results
    print('Found ${users.length} users');
    for (var user in users) {
      print('User: ${user.fullName} - ${user.email}');
    }
  } catch (e) {
    print('Error searching users: $e');
  }
}

Complete Example #

For a complete working example including both GET requests and file uploads, see the examples in the test directory:

  • test/api_test_example.dart - Main example class with implementation
  • test/run_api_test.dart - Runner for the API example
  • test/run_api_test_simple.dart - Simple direct implementation using Dio

License #

This project is licensed under the MIT License.

2
likes
130
points
72
downloads

Publisher

verified publisherdvtai.io.vn

Weekly Downloads

Network helper for request CRUD.

Repository (GitHub)

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

dio, flutter

More

Packages that depend on gtd_network