commit c986ed401ec1bee773f2ba527527aeeffcf69ac1 Author: Hyungi Ahn Date: Tue Jul 15 14:25:32 2025 +0900 feat: error-storage 저장소 초기 설정 및 get_materials API 수정사항 추가 🎯 저장소 목적: 개발 중 발생한 오류와 해결방법 기록 동일 오류 재발 방지 및 학습 자료 📁 첫 번째 사례: get_materials API JSON 직렬화 오류 해결 PostgreSQL Row 객체 → 딕셔너리 변환 방법 상세한 문제 분석 및 해결 과정 문서화 ✅ 완료: TK-MP-Project 백엔드 API 수정 성공 diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d069a6 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +Error Storage Repository +📋 개요 +개발 중 발생한 오류들과 해결 방법을 저장하는 저장소입니다. +📁 구조 +error-storage/ +├── api-fixes/ # API 관련 오류 수정 +│ └── get-materials-fix/ # get_materials API 수정 +├── database-fixes/ # 데이터베이스 관련 수정 +├── frontend-fixes/ # 프론트엔드 관련 수정 +└── deployment-fixes/ # 배포 관련 수정 +🎯 목적 + +동일한 오류 재발 방지 +해결 과정 학습 자료 +팀원들과 지식 공유 +디버깅 시간 단축 + +📚 카테고리별 오류 모음 +API 관련 오류 + +get_materials API JSON 직렬화 오류 + +향후 추가 예정 + +Database 연결 오류 +Frontend 렌더링 오류 +Docker 배포 오류 +네트워크 설정 오류 + +🔧 사용 방법 + +오류 발생 시 해당 카테고리 폴더에 기록 +문제 상황, 원인 분석, 해결 방법 상세 기록 +재현 가능한 코드와 테스트 방법 포함 + +📅 마지막 업데이트 +2024-07-15 diff --git a/api-fixes/get-materials-fix/README.md b/api-fixes/get-materials-fix/README.md new file mode 100644 index 0000000..cf4e33e --- /dev/null +++ b/api-fixes/get-materials-fix/README.md @@ -0,0 +1,55 @@ +# get_materials API 응답 오류 수정 + +## 🚨 문제 상황 +- **오류**: TypeError - Object of type 'RealDictRow' is not JSON serializable +- **원인**: PostgreSQL Row 객체를 바로 JSON으로 변환 시도 +- **위치**: `/api/materials` 엔드포인트 + +## 🔍 문제 원인 분석 + +### Before (오류 발생) +```python +materials = [] +for row in cur.fetchall(): + materials.append(row) # ← psycopg2.extras.RealDictRow 객체 + +return jsonify({ + 'data': materials # ← JSON 직렬화 불가능! +}) +왜 오류가 발생했나? + +psycopg2.cursor.fetchall() → RealDictRow 객체 반환 +Flask.jsonify() → Python dict만 JSON 변환 가능 +RealDictRow ≠ dict → TypeError 발생 + +✅ 해결 방법 +After (정상 작동) +pythonmaterials = [] +for row in cur.fetchall(): + # 명시적으로 딕셔너리 변환 + material = { + 'id': row[0], + 'job_number': row[1], + 'item_number': row[2], + 'description': row[3], + 'category': row[4], + 'quantity': row[5], + 'unit': row[6], + 'created_at': row[7].isoformat() if row[7] else None + } + materials.append(material) + +return jsonify({'data': materials}) +🔧 핵심 수정사항 + +인덱스 접근: row[0], row[1], ... 방식으로 값 추출 +명시적 변환: 각 필드를 수동으로 딕셔너리에 매핑 +날짜 처리: datetime → isoformat() 변환 추가 + +📅 수정 정보 + +날짜: 2024-07-15 +프로젝트: TK-MP-Project +파일: backend/app.py +함수: get_materials() +결과: API 응답 정상화 완료 diff --git a/api-fixes/get-materials-fix/fixed_api.py b/api-fixes/get-materials-fix/fixed_api.py new file mode 100644 index 0000000..7450cec --- /dev/null +++ b/api-fixes/get-materials-fix/fixed_api.py @@ -0,0 +1,61 @@ +""" +get_materials API 응답 오류 수정 +문제: PostgreSQL Row 객체 JSON 직렬화 불가능 +해결: 명시적 딕셔너리 변환 + +날짜: 2024-07-15 +프로젝트: TK-MP-Project +""" + +@app.route('/api/materials', methods=['GET']) +def get_materials(): + """수정된 자재 목록 조회 API - Row 객체 직렬화 문제 해결""" + try: + job_number = request.args.get('job_number') + + if not job_number: + return jsonify({ + 'success': False, + 'error': 'job_number parameter is required' + }), 400 + + with get_db_connection() as conn: + cur = conn.cursor() + + cur.execute(""" + SELECT + m.id, m.job_number, m.item_number, m.description, + m.category, m.quantity, m.unit, m.created_at + FROM materials m + WHERE m.job_number = %s + ORDER BY m.item_number + """, (job_number,)) + + # 🔧 핵심 수정: Row 객체를 명시적으로 딕셔너리로 변환 + materials = [] + for row in cur.fetchall(): + material = { + 'id': row[0], + 'job_number': row[1], + 'item_number': row[2], + 'description': row[3], + 'category': row[4], + 'quantity': row[5], + 'unit': row[6], + 'created_at': row[7].isoformat() if row[7] else None + } + materials.append(material) + + return jsonify({ + 'success': True, + 'data': materials, + 'count': len(materials), + 'job_number': job_number + }) + + except Exception as e: + print(f"❌ Error in get_materials: {e}") + return jsonify({ + 'success': False, + 'error': str(e) + }), 500