update api
This commit is contained in:
@@ -5,11 +5,12 @@ class ApiConstants {
|
||||
|
||||
// ===== Base URL Configuration =====
|
||||
/// Base URL for the API
|
||||
/// TODO: Replace with actual production URL
|
||||
static const String baseUrl = 'https://api.retailpos.example.com';
|
||||
/// Development: http://localhost:3000
|
||||
/// Production: TODO - Replace with actual production URL
|
||||
static const String baseUrl = 'http://localhost:3000';
|
||||
|
||||
/// API version prefix
|
||||
static const String apiVersion = '/api/v1';
|
||||
static const String apiVersion = '/api';
|
||||
|
||||
/// Full base URL with version
|
||||
static String get fullBaseUrl => '$baseUrl$apiVersion';
|
||||
@@ -33,8 +34,21 @@ class ApiConstants {
|
||||
|
||||
// ===== Endpoint Paths =====
|
||||
|
||||
// Authentication Endpoints
|
||||
/// POST - Login user
|
||||
static const String login = '/auth/login';
|
||||
|
||||
/// POST - Register new user
|
||||
static const String register = '/auth/register';
|
||||
|
||||
/// GET - Get current user profile (requires auth)
|
||||
static const String profile = '/auth/profile';
|
||||
|
||||
/// POST - Refresh access token (requires auth)
|
||||
static const String refreshToken = '/auth/refresh';
|
||||
|
||||
// Products Endpoints
|
||||
/// GET - Fetch all products
|
||||
/// GET - Fetch all products (with pagination and filters)
|
||||
static const String products = '/products';
|
||||
|
||||
/// GET - Fetch single product by ID
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import '../../features/auth/data/datasources/auth_remote_datasource.dart';
|
||||
import '../../features/auth/data/repositories/auth_repository_impl.dart';
|
||||
import '../../features/auth/domain/repositories/auth_repository.dart';
|
||||
import '../network/dio_client.dart';
|
||||
import '../network/network_info.dart';
|
||||
import '../storage/secure_storage.dart';
|
||||
|
||||
/// Service locator instance
|
||||
final sl = GetIt.instance;
|
||||
@@ -28,12 +32,33 @@ Future<void> initDependencies() async {
|
||||
() => DioClient(),
|
||||
);
|
||||
|
||||
// Secure Storage
|
||||
sl.registerLazySingleton<SecureStorage>(
|
||||
() => SecureStorage(),
|
||||
);
|
||||
|
||||
// ===== Authentication Feature =====
|
||||
|
||||
// Auth Remote Data Source
|
||||
sl.registerLazySingleton<AuthRemoteDataSource>(
|
||||
() => AuthRemoteDataSourceImpl(dioClient: sl()),
|
||||
);
|
||||
|
||||
// Auth Repository
|
||||
sl.registerLazySingleton<AuthRepository>(
|
||||
() => AuthRepositoryImpl(
|
||||
remoteDataSource: sl(),
|
||||
secureStorage: sl(),
|
||||
dioClient: sl(),
|
||||
),
|
||||
);
|
||||
|
||||
// ===== Data Sources =====
|
||||
// Note: Data sources are managed by Riverpod providers
|
||||
// Note: Other data sources are managed by Riverpod providers
|
||||
// No direct registration needed here
|
||||
|
||||
// ===== Repositories =====
|
||||
// TODO: Register repositories when they are implemented
|
||||
// TODO: Register other repositories when they are implemented
|
||||
|
||||
// ===== Use Cases =====
|
||||
// TODO: Register use cases when they are implemented
|
||||
|
||||
@@ -28,3 +28,23 @@ class UnauthorizedException implements Exception {
|
||||
final String message;
|
||||
UnauthorizedException([this.message = 'Unauthorized access']);
|
||||
}
|
||||
|
||||
class AuthenticationException implements Exception {
|
||||
final String message;
|
||||
AuthenticationException([this.message = 'Authentication failed']);
|
||||
}
|
||||
|
||||
class InvalidCredentialsException implements Exception {
|
||||
final String message;
|
||||
InvalidCredentialsException([this.message = 'Invalid email or password']);
|
||||
}
|
||||
|
||||
class TokenExpiredException implements Exception {
|
||||
final String message;
|
||||
TokenExpiredException([this.message = 'Token has expired']);
|
||||
}
|
||||
|
||||
class ConflictException implements Exception {
|
||||
final String message;
|
||||
ConflictException([this.message = 'Resource already exists']);
|
||||
}
|
||||
|
||||
@@ -39,3 +39,23 @@ class NotFoundFailure extends Failure {
|
||||
class UnauthorizedFailure extends Failure {
|
||||
const UnauthorizedFailure([super.message = 'Unauthorized access']);
|
||||
}
|
||||
|
||||
/// Authentication failure
|
||||
class AuthenticationFailure extends Failure {
|
||||
const AuthenticationFailure([super.message = 'Authentication failed']);
|
||||
}
|
||||
|
||||
/// Invalid credentials failure
|
||||
class InvalidCredentialsFailure extends Failure {
|
||||
const InvalidCredentialsFailure([super.message = 'Invalid email or password']);
|
||||
}
|
||||
|
||||
/// Token expired failure
|
||||
class TokenExpiredFailure extends Failure {
|
||||
const TokenExpiredFailure([super.message = 'Token has expired']);
|
||||
}
|
||||
|
||||
/// Conflict failure (e.g., email already exists)
|
||||
class ConflictFailure extends Failure {
|
||||
const ConflictFailure([super.message = 'Resource already exists']);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'api_interceptor.dart';
|
||||
/// Dio HTTP client configuration
|
||||
class DioClient {
|
||||
late final Dio _dio;
|
||||
String? _authToken;
|
||||
|
||||
DioClient() {
|
||||
_dio = Dio(
|
||||
@@ -21,10 +22,35 @@ class DioClient {
|
||||
);
|
||||
|
||||
_dio.interceptors.add(ApiInterceptor());
|
||||
|
||||
// Add auth interceptor to inject token
|
||||
_dio.interceptors.add(
|
||||
InterceptorsWrapper(
|
||||
onRequest: (options, handler) {
|
||||
if (_authToken != null) {
|
||||
options.headers[ApiConstants.authorization] = 'Bearer $_authToken';
|
||||
}
|
||||
return handler.next(options);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Dio get dio => _dio;
|
||||
|
||||
/// Set authentication token for all future requests
|
||||
void setAuthToken(String token) {
|
||||
_authToken = token;
|
||||
}
|
||||
|
||||
/// Clear authentication token
|
||||
void clearAuthToken() {
|
||||
_authToken = null;
|
||||
}
|
||||
|
||||
/// Check if auth token is set
|
||||
bool get hasAuthToken => _authToken != null;
|
||||
|
||||
/// GET request
|
||||
Future<Response> get(
|
||||
String path, {
|
||||
|
||||
60
lib/core/storage/secure_storage.dart
Normal file
60
lib/core/storage/secure_storage.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
/// Secure storage service for storing sensitive data like JWT tokens
|
||||
class SecureStorage {
|
||||
final FlutterSecureStorage _storage;
|
||||
|
||||
// Storage keys
|
||||
static const String _accessTokenKey = 'access_token';
|
||||
static const String _refreshTokenKey = 'refresh_token';
|
||||
|
||||
SecureStorage({FlutterSecureStorage? storage})
|
||||
: _storage = storage ?? const FlutterSecureStorage();
|
||||
|
||||
/// Save access token
|
||||
Future<void> saveAccessToken(String token) async {
|
||||
await _storage.write(key: _accessTokenKey, value: token);
|
||||
}
|
||||
|
||||
/// Get access token
|
||||
Future<String?> getAccessToken() async {
|
||||
return await _storage.read(key: _accessTokenKey);
|
||||
}
|
||||
|
||||
/// Save refresh token (for future use)
|
||||
Future<void> saveRefreshToken(String token) async {
|
||||
await _storage.write(key: _refreshTokenKey, value: token);
|
||||
}
|
||||
|
||||
/// Get refresh token (for future use)
|
||||
Future<String?> getRefreshToken() async {
|
||||
return await _storage.read(key: _refreshTokenKey);
|
||||
}
|
||||
|
||||
/// Delete access token
|
||||
Future<void> deleteAccessToken() async {
|
||||
await _storage.delete(key: _accessTokenKey);
|
||||
}
|
||||
|
||||
/// Delete refresh token
|
||||
Future<void> deleteRefreshToken() async {
|
||||
await _storage.delete(key: _refreshTokenKey);
|
||||
}
|
||||
|
||||
/// Delete all tokens (logout)
|
||||
Future<void> deleteAllTokens() async {
|
||||
await _storage.delete(key: _accessTokenKey);
|
||||
await _storage.delete(key: _refreshTokenKey);
|
||||
}
|
||||
|
||||
/// Check if access token exists
|
||||
Future<bool> hasAccessToken() async {
|
||||
final token = await getAccessToken();
|
||||
return token != null && token.isNotEmpty;
|
||||
}
|
||||
|
||||
/// Clear all secure storage
|
||||
Future<void> clearAll() async {
|
||||
await _storage.deleteAll();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user