This commit is contained in:
2025-10-28 00:09:46 +07:00
parent 9ebe7c2919
commit de49f564b1
110 changed files with 15392 additions and 3996 deletions

257
QUICK_REFERENCE.md Normal file
View File

@@ -0,0 +1,257 @@
# API Client Quick Reference
## Import
```dart
import 'package:minhthu/core/core.dart';
```
## Initialization
```dart
final secureStorage = SecureStorage();
final apiClient = ApiClient(
secureStorage,
onUnauthorized: () => context.go('/login'),
);
```
## HTTP Methods
### GET Request
```dart
final response = await apiClient.get(
'/warehouses',
queryParameters: {'limit': 10},
);
```
### POST Request
```dart
final response = await apiClient.post(
'/auth/login',
data: {'username': 'user', 'password': 'pass'},
);
```
### PUT Request
```dart
final response = await apiClient.put(
'/products/123',
data: {'name': 'Updated'},
);
```
### DELETE Request
```dart
final response = await apiClient.delete('/products/123');
```
## Parse API Response
```dart
final apiResponse = ApiResponse.fromJson(
response.data,
(json) => User.fromJson(json), // or your model
);
if (apiResponse.isSuccess && apiResponse.value != null) {
final data = apiResponse.value;
// Use data
} else {
final error = apiResponse.getErrorMessage();
// Handle error
}
```
## Error Handling
```dart
try {
final response = await apiClient.get('/products');
} on NetworkException catch (e) {
// Timeout, no internet
print('Network error: ${e.message}');
} on ServerException catch (e) {
// HTTP errors (401, 404, 500, etc.)
print('Server error: ${e.message}');
print('Error code: ${e.code}');
}
```
## Token Management
### Save Token
```dart
await secureStorage.saveAccessToken('your_token');
await secureStorage.saveRefreshToken('refresh_token');
```
### Get Token
```dart
final token = await secureStorage.getAccessToken();
```
### Check Authentication
```dart
final isAuthenticated = await apiClient.isAuthenticated();
```
### Clear Tokens (Logout)
```dart
await apiClient.clearAuth();
```
## API Endpoints
Use constants from `ApiEndpoints`:
```dart
// Authentication
ApiEndpoints.login // /auth/login
ApiEndpoints.logout // /auth/logout
// Warehouses
ApiEndpoints.warehouses // /warehouses
ApiEndpoints.warehouseById(1) // /warehouses/1
// Products
ApiEndpoints.products // /products
ApiEndpoints.productById(123) // /products/123
// Query parameters helper
ApiEndpoints.productQueryParams(
warehouseId: 1,
type: 'import',
) // {warehouseId: 1, type: 'import'}
```
## Utilities
### Test Connection
```dart
final isConnected = await apiClient.testConnection();
```
### Update Base URL
```dart
apiClient.updateBaseUrl('https://dev-api.example.com');
```
### Get Current Token
```dart
final token = await apiClient.getAccessToken();
```
## Common Patterns
### Login Flow
```dart
// 1. Login
final response = await apiClient.post(
ApiEndpoints.login,
data: {'username': username, 'password': password},
);
// 2. Parse
final apiResponse = ApiResponse.fromJson(
response.data,
(json) => User.fromJson(json),
);
// 3. Save tokens
if (apiResponse.isSuccess && apiResponse.value != null) {
final user = apiResponse.value!;
await secureStorage.saveAccessToken(user.accessToken);
await secureStorage.saveUserId(user.userId);
}
```
### Repository Pattern
```dart
class WarehouseRemoteDataSourceImpl implements WarehouseRemoteDataSource {
final ApiClient apiClient;
WarehouseRemoteDataSourceImpl(this.apiClient);
@override
Future<List<Warehouse>> getWarehouses() async {
final response = await apiClient.get(ApiEndpoints.warehouses);
final apiResponse = ApiResponse.fromJson(
response.data,
(json) => (json as List).map((e) => Warehouse.fromJson(e)).toList(),
);
if (apiResponse.isSuccess && apiResponse.value != null) {
return apiResponse.value!;
} else {
throw ServerException(apiResponse.getErrorMessage());
}
}
}
```
## Configuration
### Set Base URL
In `lib/core/constants/app_constants.dart`:
```dart
static const String apiBaseUrl = 'https://api.example.com';
```
### Set Timeouts
In `lib/core/constants/app_constants.dart`:
```dart
static const int connectionTimeout = 30000; // 30 seconds
static const int receiveTimeout = 30000;
static const int sendTimeout = 30000;
```
## Files Location
- API Client: `/lib/core/network/api_client.dart`
- API Response: `/lib/core/network/api_response.dart`
- Secure Storage: `/lib/core/storage/secure_storage.dart`
- API Endpoints: `/lib/core/constants/api_endpoints.dart`
- Examples: `/lib/core/network/api_client_example.dart`
- Documentation: `/lib/core/network/README.md`
## Important Notes
1. **Automatic Token Injection**: Bearer token is automatically added to all requests
2. **401 Handling**: 401 errors automatically clear tokens and trigger `onUnauthorized` callback
3. **Logging**: All requests/responses are logged with sensitive data redacted
4. **Singleton Storage**: SecureStorage is a singleton - use `SecureStorage()` everywhere
5. **Error Codes**: ServerException includes error codes (e.g., '401', '404', '500')
## Common Issues
### Token not injected?
Check if token exists: `await secureStorage.getAccessToken()`
### 401 not clearing tokens?
Verify `onUnauthorized` callback is set in ApiClient constructor
### Connection timeout?
Check network, verify base URL, increase timeout in constants
### Logs not showing?
Check Flutter DevTools console or developer.log output