fill
This commit is contained in:
257
QUICK_REFERENCE.md
Normal file
257
QUICK_REFERENCE.md
Normal 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
|
||||
Reference in New Issue
Block a user