feat: API 통합을 위한 기초 인프라 구축
- 네트워크 레이어 구현 (Dio 기반 ApiClient) - 환경별 설정 관리 시스템 구축 - 의존성 주입 설정 (GetIt) - API 엔드포인트 상수 정의 - 인터셉터 구현 (Auth, Error, Logging) - 프로젝트 아키텍처 개선 (core, data, di 디렉토리 구조) - API 통합 계획서 및 요구사항 문서 작성 - 필요 패키지 추가 (dio, flutter_secure_storage, get_it 등)
This commit is contained in:
212
lib/data/datasources/remote/api_client.dart
Normal file
212
lib/data/datasources/remote/api_client.dart
Normal file
@@ -0,0 +1,212 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../../../core/config/environment.dart';
|
||||
import 'interceptors/auth_interceptor.dart';
|
||||
import 'interceptors/error_interceptor.dart';
|
||||
import 'interceptors/logging_interceptor.dart';
|
||||
|
||||
/// API 클라이언트 클래스
|
||||
class ApiClient {
|
||||
late final Dio _dio;
|
||||
|
||||
static final ApiClient _instance = ApiClient._internal();
|
||||
|
||||
factory ApiClient() => _instance;
|
||||
|
||||
ApiClient._internal() {
|
||||
_dio = Dio(_baseOptions);
|
||||
_setupInterceptors();
|
||||
}
|
||||
|
||||
/// Dio 인스턴스 getter
|
||||
Dio get dio => _dio;
|
||||
|
||||
/// 기본 옵션 설정
|
||||
BaseOptions get _baseOptions => BaseOptions(
|
||||
baseUrl: Environment.apiBaseUrl,
|
||||
connectTimeout: Duration(milliseconds: Environment.apiTimeout),
|
||||
receiveTimeout: Duration(milliseconds: Environment.apiTimeout),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
validateStatus: (status) {
|
||||
return status != null && status < 500;
|
||||
},
|
||||
);
|
||||
|
||||
/// 인터셉터 설정
|
||||
void _setupInterceptors() {
|
||||
_dio.interceptors.clear();
|
||||
|
||||
// 인증 인터셉터
|
||||
_dio.interceptors.add(AuthInterceptor());
|
||||
|
||||
// 에러 처리 인터셉터
|
||||
_dio.interceptors.add(ErrorInterceptor());
|
||||
|
||||
// 로깅 인터셉터 (개발 환경에서만)
|
||||
if (Environment.enableLogging && kDebugMode) {
|
||||
_dio.interceptors.add(LoggingInterceptor());
|
||||
}
|
||||
}
|
||||
|
||||
/// 토큰 업데이트
|
||||
void updateAuthToken(String token) {
|
||||
_dio.options.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
|
||||
/// 토큰 제거
|
||||
void removeAuthToken() {
|
||||
_dio.options.headers.remove('Authorization');
|
||||
}
|
||||
|
||||
/// GET 요청
|
||||
Future<Response<T>> get<T>(
|
||||
String path, {
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) {
|
||||
return _dio.get<T>(
|
||||
path,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
}
|
||||
|
||||
/// POST 요청
|
||||
Future<Response<T>> post<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onSendProgress,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) {
|
||||
return _dio.post<T>(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
onSendProgress: onSendProgress,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
}
|
||||
|
||||
/// PUT 요청
|
||||
Future<Response<T>> put<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onSendProgress,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) {
|
||||
return _dio.put<T>(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
onSendProgress: onSendProgress,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
}
|
||||
|
||||
/// PATCH 요청
|
||||
Future<Response<T>> patch<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onSendProgress,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) {
|
||||
return _dio.patch<T>(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
onSendProgress: onSendProgress,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
}
|
||||
|
||||
/// DELETE 요청
|
||||
Future<Response<T>> delete<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
}) {
|
||||
return _dio.delete<T>(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
}
|
||||
|
||||
/// 파일 업로드
|
||||
Future<Response<T>> uploadFile<T>(
|
||||
String path, {
|
||||
required String filePath,
|
||||
required String fileFieldName,
|
||||
Map<String, dynamic>? additionalData,
|
||||
ProgressCallback? onSendProgress,
|
||||
CancelToken? cancelToken,
|
||||
}) async {
|
||||
final fileName = filePath.split('/').last;
|
||||
final formData = FormData.fromMap({
|
||||
fileFieldName: await MultipartFile.fromFile(
|
||||
filePath,
|
||||
filename: fileName,
|
||||
),
|
||||
...?additionalData,
|
||||
});
|
||||
|
||||
return _dio.post<T>(
|
||||
path,
|
||||
data: formData,
|
||||
options: Options(
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
),
|
||||
onSendProgress: onSendProgress,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
}
|
||||
|
||||
/// 파일 다운로드
|
||||
Future<Response> downloadFile(
|
||||
String path, {
|
||||
required String savePath,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
CancelToken? cancelToken,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
}) {
|
||||
return _dio.download(
|
||||
path,
|
||||
savePath,
|
||||
queryParameters: queryParameters,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
cancelToken: cancelToken,
|
||||
options: Options(
|
||||
responseType: ResponseType.bytes,
|
||||
followRedirects: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user