Showing
2 changed files
with
117 additions
and
1 deletions
| ... | @@ -1156,6 +1156,86 @@ if self.isUserAuthenticated() { | ... | @@ -1156,6 +1156,86 @@ if self.isUserAuthenticated() { | 
| 1156 | **Result**: ✅ **No more ERROR: -1** - campaigns load successfully for both authenticated and non-authenticated users | 1156 | **Result**: ✅ **No more ERROR: -1** - campaigns load successfully for both authenticated and non-authenticated users | 
| 1157 | 1157 | ||
| 1158 | --- | 1158 | --- | 
| 1159 | + | ||
| 1160 | +#### **Issue #8: Central Context Response Parsing (FINAL SOLUTION)** | ||
| 1161 | +**File**: `SwiftWarplyFramework/SwiftWarplyFramework/Network/NetworkService.swift` | ||
| 1162 | +**Problem**: All context endpoints failed due to incorrect response structure parsing - looking for data at wrong level | ||
| 1163 | +**Impact**: ❌ **CRITICAL** - Multiple endpoints failing with ERROR: -1 due to response parsing issues | ||
| 1164 | + | ||
| 1165 | +**Root Cause**: The server returns responses in format `{"status": "1", "context": {...}}` but the code expected data at top level. | ||
| 1166 | + | ||
| 1167 | +**Example Response Structure**: | ||
| 1168 | +```json | ||
| 1169 | +{ | ||
| 1170 | + "status": "1", | ||
| 1171 | + "context": { | ||
| 1172 | + "MAPP_CAMPAIGNING-status": 1, | ||
| 1173 | + "MAPP_CAMPAIGNING": { "campaigns": [...] }, | ||
| 1174 | + "events_processed": 1 | ||
| 1175 | + } | ||
| 1176 | +} | ||
| 1177 | +``` | ||
| 1178 | + | ||
| 1179 | +**Solution**: **Central Response Transformation in NetworkService** | ||
| 1180 | +```swift | ||
| 1181 | +/// Transform context-wrapped responses to flatten structure for backward compatibility | ||
| 1182 | +private func transformContextResponse(_ response: [String: Any]) -> [String: Any] { | ||
| 1183 | + // Detect context response pattern: {"status": "1", "context": {...}} | ||
| 1184 | + if let statusString = response["status"] as? String, | ||
| 1185 | + let context = response["context"] as? [String: Any] { | ||
| 1186 | + | ||
| 1187 | + print("🔄 [NetworkService] Detected context response - transforming structure") | ||
| 1188 | + | ||
| 1189 | + // Start with context content | ||
| 1190 | + var transformedResponse = context | ||
| 1191 | + | ||
| 1192 | + // Convert string status to integer for backward compatibility | ||
| 1193 | + transformedResponse["status"] = (statusString == "1") ? 1 : 0 | ||
| 1194 | + | ||
| 1195 | + // Preserve any other top-level fields (like events_processed) | ||
| 1196 | + for (key, value) in response { | ||
| 1197 | + if key != "context" && key != "status" { | ||
| 1198 | + transformedResponse[key] = value | ||
| 1199 | + } | ||
| 1200 | + } | ||
| 1201 | + | ||
| 1202 | + return transformedResponse | ||
| 1203 | + } | ||
| 1204 | + | ||
| 1205 | + // Return unchanged if not a context response | ||
| 1206 | + return response | ||
| 1207 | +} | ||
| 1208 | +``` | ||
| 1209 | + | ||
| 1210 | +**Integration**: Added to `requestRaw` method in NetworkService: | ||
| 1211 | +```swift | ||
| 1212 | +public func requestRaw(_ endpoint: Endpoint) async throws -> [String: Any] { | ||
| 1213 | + let data = try await performRequest(endpoint) | ||
| 1214 | + | ||
| 1215 | + do { | ||
| 1216 | + guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { | ||
| 1217 | + throw NetworkError.invalidResponse | ||
| 1218 | + } | ||
| 1219 | + | ||
| 1220 | + // Transform context-wrapped responses for backward compatibility | ||
| 1221 | + let transformedResponse = transformContextResponse(json) | ||
| 1222 | + return transformedResponse | ||
| 1223 | + } catch { | ||
| 1224 | + throw NetworkError.decodingError(error) | ||
| 1225 | + } | ||
| 1226 | +} | ||
| 1227 | +``` | ||
| 1228 | + | ||
| 1229 | +**Key Benefits**: | ||
| 1230 | +1. **Central Fix** - One solution fixes all context endpoints automatically | ||
| 1231 | +2. **Smart Detection** - Automatically detects context responses vs regular responses | ||
| 1232 | +3. **Backward Compatible** - Non-context responses pass through unchanged | ||
| 1233 | +4. **Future-Proof** - New context endpoints work automatically | ||
| 1234 | +5. **Zero Breaking Changes** - All existing code continues to work | ||
| 1235 | + | ||
| 1236 | +**Result**: ✅ **Universal fix for all context response parsing issues** - getCampaigns and all other context endpoints now work correctly | ||
| 1237 | + | ||
| 1238 | +--- | ||
| 1159 | ### **🔧 Additional Safety Fixes - June 27, 2025 (Session 2)** | 1239 | ### **🔧 Additional Safety Fixes - June 27, 2025 (Session 2)** | 
| 1160 | 1240 | ||
| 1161 | After the initial legacy credential removal, a comprehensive search revealed **3 additional problematic checks** that could still cause issues: | 1241 | After the initial legacy credential removal, a comprehensive search revealed **3 additional problematic checks** that could still cause issues: | ... | ... | 
| ... | @@ -141,7 +141,10 @@ public final class NetworkService: NetworkServiceProtocol { | ... | @@ -141,7 +141,10 @@ public final class NetworkService: NetworkServiceProtocol { | 
| 141 | guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { | 141 | guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { | 
| 142 | throw NetworkError.invalidResponse | 142 | throw NetworkError.invalidResponse | 
| 143 | } | 143 | } | 
| 144 | - return json | 144 | + | 
| 145 | + // Transform context-wrapped responses for backward compatibility | ||
| 146 | + let transformedResponse = transformContextResponse(json) | ||
| 147 | + return transformedResponse | ||
| 145 | } catch { | 148 | } catch { | 
| 146 | throw NetworkError.decodingError(error) | 149 | throw NetworkError.decodingError(error) | 
| 147 | } | 150 | } | 
| ... | @@ -177,6 +180,39 @@ public final class NetworkService: NetworkServiceProtocol { | ... | @@ -177,6 +180,39 @@ public final class NetworkService: NetworkServiceProtocol { | 
| 177 | 180 | ||
| 178 | // MARK: - Private Methods | 181 | // MARK: - Private Methods | 
| 179 | 182 | ||
| 183 | + /// Transform context-wrapped responses to flatten structure for backward compatibility | ||
| 184 | + /// Detects responses with pattern: {"status": "1", "context": {...}} and flattens them | ||
| 185 | + private func transformContextResponse(_ response: [String: Any]) -> [String: Any] { | ||
| 186 | + // Detect context response pattern: {"status": "1", "context": {...}} | ||
| 187 | + if let statusString = response["status"] as? String, | ||
| 188 | + let context = response["context"] as? [String: Any] { | ||
| 189 | + | ||
| 190 | + print("🔄 [NetworkService] Detected context response - transforming structure") | ||
| 191 | + | ||
| 192 | + // Start with context content | ||
| 193 | + var transformedResponse = context | ||
| 194 | + | ||
| 195 | + // Convert string status to integer for backward compatibility | ||
| 196 | + transformedResponse["status"] = (statusString == "1") ? 1 : 0 | ||
| 197 | + | ||
| 198 | + // Preserve any other top-level fields (like events_processed) | ||
| 199 | + for (key, value) in response { | ||
| 200 | + if key != "context" && key != "status" { | ||
| 201 | + transformedResponse[key] = value | ||
| 202 | + } | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + print("✅ [NetworkService] Context response transformed successfully") | ||
| 206 | + print(" Original keys: \(Array(response.keys).sorted())") | ||
| 207 | + print(" Transformed keys: \(Array(transformedResponse.keys).sorted())") | ||
| 208 | + | ||
| 209 | + return transformedResponse | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + // Return unchanged if not a context response | ||
| 213 | + return response | ||
| 214 | + } | ||
| 215 | + | ||
| 180 | private func performRequest(_ endpoint: Endpoint) async throws -> Data { | 216 | private func performRequest(_ endpoint: Endpoint) async throws -> Data { | 
| 181 | // Check network connectivity | 217 | // Check network connectivity | 
| 182 | guard isConnected else { | 218 | guard isConnected else { | ... | ... | 
- 
Please register or login to post a comment