This commit is contained in:
2025-09-28 00:20:44 +07:00
parent 74d0e3d44c
commit cb53f5585b
10 changed files with 1098 additions and 160 deletions

View File

@@ -1,29 +1,22 @@
import '../constants/environment_config.dart';
/// API constants for network configuration
class ApiConstants {
// Private constructor to prevent instantiation
const ApiConstants._();
// Base URLs for different environments
static const String baseUrlDev = 'https://api-dev.example.com';
static const String baseUrlStaging = 'https://api-staging.example.com';
static const String baseUrlProd = 'https://api.example.com';
// Environment-based configuration
static String get baseUrl => EnvironmentConfig.baseUrl;
static String get apiPath => EnvironmentConfig.apiPath;
// Current environment base URL
// In a real app, this would be determined by build configuration
static const String baseUrl = baseUrlDev;
// Timeout configurations (environment-specific)
static int get connectTimeout => EnvironmentConfig.connectTimeout;
static int get receiveTimeout => EnvironmentConfig.receiveTimeout;
static int get sendTimeout => EnvironmentConfig.sendTimeout;
// API versioning
static const String apiVersion = 'v1';
static const String apiPath = '/api/$apiVersion';
// Timeout configurations (in milliseconds)
static const int connectTimeout = 30000; // 30 seconds
static const int receiveTimeout = 30000; // 30 seconds
static const int sendTimeout = 30000; // 30 seconds
// Retry configurations
static const int maxRetries = 3;
static const Duration retryDelay = Duration(seconds: 1);
// Retry configurations (environment-specific)
static int get maxRetries => EnvironmentConfig.maxRetries;
static Duration get retryDelay => EnvironmentConfig.retryDelay;
// Headers
static const String contentType = 'application/json';
@@ -35,11 +28,12 @@ class ApiConstants {
static const String bearerPrefix = 'Bearer';
static const String apiKeyHeaderKey = 'X-API-Key';
// Common API endpoints
static const String authEndpoint = '/auth';
static const String loginEndpoint = '$authEndpoint/login';
static const String refreshEndpoint = '$authEndpoint/refresh';
static const String logoutEndpoint = '$authEndpoint/logout';
// Authentication endpoints (from environment config)
static String get authEndpoint => EnvironmentConfig.authEndpoint;
static String get loginEndpoint => EnvironmentConfig.loginEndpoint;
static String get registerEndpoint => EnvironmentConfig.registerEndpoint;
static String get refreshEndpoint => EnvironmentConfig.refreshEndpoint;
static String get logoutEndpoint => EnvironmentConfig.logoutEndpoint;
static const String userEndpoint = '/user';
static const String profileEndpoint = '$userEndpoint/profile';
@@ -68,9 +62,10 @@ class ApiConstants {
// Example: 'sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
];
// Development flags
static const bool enableLogging = true;
static const bool enableCertificatePinning = false; // Disabled for development
// Development flags (environment-specific)
static bool get enableLogging => EnvironmentConfig.enableLogging;
static bool get enableCertificatePinning => EnvironmentConfig.enableCertificatePinning;
static bool get enableDetailedLogging => EnvironmentConfig.enableDetailedLogging;
// API rate limiting
static const int maxRequestsPerMinute = 100;

View File

@@ -0,0 +1,242 @@
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import '../constants/environment_config.dart';
import 'api_constants.dart';
import 'dio_client.dart';
/// Example authentication service demonstrating the localhost:3000 configuration
/// This service shows how to use the updated API configuration with the backend
class AuthServiceExample {
final DioClient _dioClient;
AuthServiceExample(this._dioClient);
/// Test connection to the backend
Future<Map<String, dynamic>> testConnection() async {
try {
debugPrint('🔍 Testing connection to ${EnvironmentConfig.baseUrl}...');
final response = await _dioClient.get('/');
return {
'status': 'success',
'message': 'Connected to backend successfully',
'baseUrl': EnvironmentConfig.baseUrl,
'statusCode': response.statusCode,
'timestamp': DateTime.now().toIso8601String(),
};
} catch (error) {
debugPrint('❌ Connection test failed: $error');
return {
'status': 'error',
'message': 'Failed to connect to backend',
'error': error.toString(),
'baseUrl': EnvironmentConfig.baseUrl,
'timestamp': DateTime.now().toIso8601String(),
};
}
}
/// Login with email and password
/// Calls POST localhost:3000/auth/login
Future<Map<String, dynamic>> login({
required String email,
required String password,
}) async {
try {
debugPrint('🔐 Attempting login to ${EnvironmentConfig.loginUrl}...');
final response = await _dioClient.post(
ApiConstants.loginEndpoint, // This resolves to /auth/login
data: {
'email': email,
'password': password,
},
);
debugPrint('✅ Login successful');
return {
'status': 'success',
'data': response.data,
'endpoint': EnvironmentConfig.loginUrl,
'timestamp': DateTime.now().toIso8601String(),
};
} on DioException catch (dioError) {
debugPrint('❌ Login failed with DioException: ${dioError.message}');
return {
'status': 'error',
'error': dioError.message ?? 'Unknown Dio error',
'statusCode': dioError.response?.statusCode,
'endpoint': EnvironmentConfig.loginUrl,
'timestamp': DateTime.now().toIso8601String(),
};
} catch (error) {
debugPrint('❌ Login failed: $error');
return {
'status': 'error',
'error': error.toString(),
'endpoint': EnvironmentConfig.loginUrl,
'timestamp': DateTime.now().toIso8601String(),
};
}
}
/// Register new user
/// Calls POST localhost:3000/auth/register
Future<Map<String, dynamic>> register({
required String email,
required String password,
required String name,
}) async {
try {
debugPrint('📝 Attempting registration to ${EnvironmentConfig.registerUrl}...');
final response = await _dioClient.post(
ApiConstants.registerEndpoint, // This resolves to /auth/register
data: {
'email': email,
'password': password,
'name': name,
},
);
debugPrint('✅ Registration successful');
return {
'status': 'success',
'data': response.data,
'endpoint': EnvironmentConfig.registerUrl,
'timestamp': DateTime.now().toIso8601String(),
};
} on DioException catch (dioError) {
debugPrint('❌ Registration failed with DioException: ${dioError.message}');
return {
'status': 'error',
'error': dioError.message ?? 'Unknown Dio error',
'statusCode': dioError.response?.statusCode,
'endpoint': EnvironmentConfig.registerUrl,
'timestamp': DateTime.now().toIso8601String(),
};
} catch (error) {
debugPrint('❌ Registration failed: $error');
return {
'status': 'error',
'error': error.toString(),
'endpoint': EnvironmentConfig.registerUrl,
'timestamp': DateTime.now().toIso8601String(),
};
}
}
/// Refresh authentication token
/// Calls POST localhost:3000/auth/refresh
Future<Map<String, dynamic>> refreshToken(String refreshToken) async {
try {
debugPrint('🔄 Attempting token refresh to ${EnvironmentConfig.refreshUrl}...');
final response = await _dioClient.post(
ApiConstants.refreshEndpoint, // This resolves to /auth/refresh
data: {
'refreshToken': refreshToken,
},
);
debugPrint('✅ Token refresh successful');
return {
'status': 'success',
'data': response.data,
'endpoint': EnvironmentConfig.refreshUrl,
'timestamp': DateTime.now().toIso8601String(),
};
} on DioException catch (dioError) {
debugPrint('❌ Token refresh failed with DioException: ${dioError.message}');
return {
'status': 'error',
'error': dioError.message ?? 'Unknown Dio error',
'statusCode': dioError.response?.statusCode,
'endpoint': EnvironmentConfig.refreshUrl,
'timestamp': DateTime.now().toIso8601String(),
};
} catch (error) {
debugPrint('❌ Token refresh failed: $error');
return {
'status': 'error',
'error': error.toString(),
'endpoint': EnvironmentConfig.refreshUrl,
'timestamp': DateTime.now().toIso8601String(),
};
}
}
/// Logout user
/// Calls POST localhost:3000/auth/logout
Future<Map<String, dynamic>> logout(String accessToken) async {
try {
debugPrint('🚪 Attempting logout to ${EnvironmentConfig.logoutUrl}...');
final response = await _dioClient.post(
ApiConstants.logoutEndpoint, // This resolves to /auth/logout
options: Options(
headers: {
ApiConstants.authHeaderKey: '${ApiConstants.bearerPrefix} $accessToken',
},
),
);
debugPrint('✅ Logout successful');
return {
'status': 'success',
'data': response.data,
'endpoint': EnvironmentConfig.logoutUrl,
'timestamp': DateTime.now().toIso8601String(),
};
} on DioException catch (dioError) {
debugPrint('❌ Logout failed with DioException: ${dioError.message}');
return {
'status': 'error',
'error': dioError.message ?? 'Unknown Dio error',
'statusCode': dioError.response?.statusCode,
'endpoint': EnvironmentConfig.logoutUrl,
'timestamp': DateTime.now().toIso8601String(),
};
} catch (error) {
debugPrint('❌ Logout failed: $error');
return {
'status': 'error',
'error': error.toString(),
'endpoint': EnvironmentConfig.logoutUrl,
'timestamp': DateTime.now().toIso8601String(),
};
}
}
/// Get current environment configuration for debugging
Map<String, dynamic> getEnvironmentInfo() {
return {
'environment': EnvironmentConfig.currentEnvironment.name,
'baseUrl': EnvironmentConfig.baseUrl,
'apiPath': EnvironmentConfig.apiPath,
'fullBaseUrl': EnvironmentConfig.fullBaseUrl,
'endpoints': {
'login': EnvironmentConfig.loginUrl,
'register': EnvironmentConfig.registerUrl,
'refresh': EnvironmentConfig.refreshUrl,
'logout': EnvironmentConfig.logoutUrl,
},
'timeouts': {
'connect': EnvironmentConfig.connectTimeout,
'receive': EnvironmentConfig.receiveTimeout,
'send': EnvironmentConfig.sendTimeout,
},
'retry': {
'maxRetries': EnvironmentConfig.maxRetries,
'retryDelay': EnvironmentConfig.retryDelay.inMilliseconds,
},
'flags': {
'enableLogging': EnvironmentConfig.enableLogging,
'enableDetailedLogging': EnvironmentConfig.enableDetailedLogging,
'enableCertificatePinning': EnvironmentConfig.enableCertificatePinning,
},
};
}
}

View File

@@ -0,0 +1,74 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import '../constants/environment_config.dart';
/// Simple utility to test API connection
class ApiConnectionTest {
static Future<void> testConnection(BuildContext context) async {
final dio = Dio();
try {
debugPrint('🔍 Testing API connection...');
debugPrint('Base URL: ${EnvironmentConfig.baseUrl}');
debugPrint('Auth endpoint: ${EnvironmentConfig.authEndpoint}');
// Test basic connectivity to the auth endpoint
final response = await dio.get(
'${EnvironmentConfig.baseUrl}${EnvironmentConfig.authEndpoint}',
options: Options(
validateStatus: (status) => true, // Accept any status code
receiveTimeout: const Duration(seconds: 5),
),
);
debugPrint('✅ Connection successful!');
debugPrint('Status code: ${response.statusCode}');
debugPrint('Response: ${response.data}');
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('API Connected! Status: ${response.statusCode}'),
backgroundColor: Colors.green,
),
);
}
} catch (e) {
debugPrint('❌ Connection failed: $e');
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Connection failed: $e'),
backgroundColor: Colors.red,
),
);
}
}
}
/// Get current environment info as formatted string
static String getEnvironmentInfo() {
final info = EnvironmentConfig.debugInfo;
final buffer = StringBuffer();
buffer.writeln('📊 Environment Configuration:');
buffer.writeln('================================');
info.forEach((key, value) {
buffer.writeln('$key: $value');
});
buffer.writeln('================================');
buffer.writeln('\n📍 Auth Endpoints:');
buffer.writeln('Login: ${EnvironmentConfig.loginUrl}');
buffer.writeln('Register: ${EnvironmentConfig.registerUrl}');
buffer.writeln('Refresh: ${EnvironmentConfig.refreshUrl}');
buffer.writeln('Logout: ${EnvironmentConfig.logoutUrl}');
return buffer.toString();
}
/// Print environment info to console
static void printEnvironmentInfo() {
debugPrint(getEnvironmentInfo());
}
}