258 lines
5.2 KiB
Markdown
258 lines
5.2 KiB
Markdown
# 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
|