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