Files
minhthu/QUICK_REFERENCE.md
2025-10-28 00:09:46 +07:00

5.2 KiB

API Client Quick Reference

Import

import 'package:minhthu/core/core.dart';

Initialization

final secureStorage = SecureStorage();
final apiClient = ApiClient(
  secureStorage,
  onUnauthorized: () => context.go('/login'),
);

HTTP Methods

GET Request

final response = await apiClient.get(
  '/warehouses',
  queryParameters: {'limit': 10},
);

POST Request

final response = await apiClient.post(
  '/auth/login',
  data: {'username': 'user', 'password': 'pass'},
);

PUT Request

final response = await apiClient.put(
  '/products/123',
  data: {'name': 'Updated'},
);

DELETE Request

final response = await apiClient.delete('/products/123');

Parse API Response

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

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

await secureStorage.saveAccessToken('your_token');
await secureStorage.saveRefreshToken('refresh_token');

Get Token

final token = await secureStorage.getAccessToken();

Check Authentication

final isAuthenticated = await apiClient.isAuthenticated();

Clear Tokens (Logout)

await apiClient.clearAuth();

API Endpoints

Use constants from ApiEndpoints:

// 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

final isConnected = await apiClient.testConnection();

Update Base URL

apiClient.updateBaseUrl('https://dev-api.example.com');

Get Current Token

final token = await apiClient.getAccessToken();

Common Patterns

Login Flow

// 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

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:

static const String apiBaseUrl = 'https://api.example.com';

Set Timeouts

In lib/core/constants/app_constants.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