fix: API 응답 파싱 오류 수정 및 에러 처리 개선

주요 변경사항:
- 창고 관리 API 응답 구조와 DTO 불일치 수정
  - WarehouseLocationDto에 code, manager_phone 필드 추가
  - RemoteDataSource에서 API 응답을 DTO 구조에 맞게 변환
- 회사 관리 API 응답 파싱 오류 수정
  - CompanyResponse의 필수 필드를 nullable로 변경
  - PaginatedResponse 구조 매핑 로직 개선
- 에러 처리 및 로깅 개선
  - Service Layer에 상세 에러 로깅 추가
  - Controller에서 에러 타입별 처리
- 새로운 유틸리티 추가
  - ResponseInterceptor: API 응답 정규화
  - DebugLogger: 디버깅 도구
  - HealthCheckService: 서버 상태 확인
- 문서화
  - API 통합 테스트 가이드
  - 에러 분석 보고서
  - 리팩토링 계획서
This commit is contained in:
JiWoong Sul
2025-07-31 19:15:39 +09:00
parent ad2c699ff7
commit f08b7fec79
89 changed files with 10521 additions and 892 deletions

View File

@@ -0,0 +1,99 @@
import 'package:dio/dio.dart';
import '../core/config/environment.dart';
import '../data/datasources/remote/api_client.dart';
/// API 헬스체크 테스트를 위한 서비스
class HealthCheckService {
final ApiClient _apiClient;
HealthCheckService({ApiClient? apiClient})
: _apiClient = apiClient ?? ApiClient();
/// 헬스체크 API 호출
Future<Map<String, dynamic>> checkHealth() async {
try {
print('=== 헬스체크 시작 ===');
print('API Base URL: ${Environment.apiBaseUrl}');
print('Full URL: ${Environment.apiBaseUrl}/health');
final response = await _apiClient.get('/health');
print('응답 상태 코드: ${response.statusCode}');
print('응답 데이터: ${response.data}');
return {
'success': true,
'data': response.data,
'statusCode': response.statusCode,
};
} on DioException catch (e) {
print('=== DioException 발생 ===');
print('에러 타입: ${e.type}');
print('에러 메시지: ${e.message}');
print('에러 응답: ${e.response?.data}');
print('에러 상태 코드: ${e.response?.statusCode}');
// CORS 에러인지 확인
if (e.type == DioExceptionType.connectionError ||
e.type == DioExceptionType.unknown) {
print('⚠️ CORS 또는 네트워크 연결 문제일 가능성이 있습니다.');
}
return {
'success': false,
'error': e.message ?? '알 수 없는 에러',
'errorType': e.type.toString(),
'statusCode': e.response?.statusCode,
'responseData': e.response?.data,
};
} catch (e) {
print('=== 일반 에러 발생 ===');
print('에러: $e');
return {
'success': false,
'error': e.toString(),
};
}
}
/// 직접 Dio로 테스트 (인터셉터 없이)
Future<Map<String, dynamic>> checkHealthDirect() async {
try {
print('=== 직접 Dio 헬스체크 시작 ===');
final dio = Dio(BaseOptions(
baseUrl: Environment.apiBaseUrl,
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
));
// 로깅 인터셉터만 추가
dio.interceptors.add(LogInterceptor(
requestBody: true,
responseBody: true,
requestHeader: true,
responseHeader: true,
error: true,
));
final response = await dio.get('/health');
return {
'success': true,
'data': response.data,
'statusCode': response.statusCode,
};
} catch (e) {
print('직접 Dio 에러: $e');
return {
'success': false,
'error': e.toString(),
};
}
}
}