diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b9460fa6..1f71ced39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ _None._ ### Internal Changes - Change the NSObject+SafeExpectations dependency to `~> 0.0.4`. [#555] +- Remove unnecessary json encoding. [#563] ## [5.0.0](https://github.com/wordpress-mobile/WordPressKit-iOS/releases/tag/5.0.0) diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 93fec4ce0..ce0182446 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -124,14 +124,15 @@ 46ABD0EA262EEE0400C7FF24 /* AppTransportSecuritySettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46ABD0E9262EEE0400C7FF24 /* AppTransportSecuritySettingsTests.swift */; }; 4A1DEF44293051BC00322608 /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A1DEF43293051BC00322608 /* LoggingTests.swift */; }; 4A1DEF46293051C600322608 /* LoggingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A1DEF45293051C600322608 /* LoggingTests.m */; }; - 4A68E3DD294070A7004AC3DC /* RemoteReaderSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */; }; - 4A68E3DF29407100004AC3DC /* RemoteReaderTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */; }; - 4A68E3E1294076C1004AC3DC /* RemoteReaderSiteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */; }; 4A68E3CD29404181004AC3DC /* RemoteBlog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3CC29404181004AC3DC /* RemoteBlog.swift */; }; 4A68E3CF29404289004AC3DC /* RemoteBlogOptionsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3CE29404289004AC3DC /* RemoteBlogOptionsHelper.swift */; }; 4A68E3D329406AA0004AC3DC /* RemoteMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D029406AA0004AC3DC /* RemoteMenu.swift */; }; 4A68E3D429406AA0004AC3DC /* RemoteMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D129406AA0004AC3DC /* RemoteMenuItem.swift */; }; 4A68E3D529406AA0004AC3DC /* RemoteMenuLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D229406AA0004AC3DC /* RemoteMenuLocation.swift */; }; + 4A68E3DD294070A7004AC3DC /* RemoteReaderSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */; }; + 4A68E3DF29407100004AC3DC /* RemoteReaderTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */; }; + 4A68E3E1294076C1004AC3DC /* RemoteReaderSiteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */; }; + 4A68E411294C0BDD004AC3DC /* Result+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E410294C0BDD004AC3DC /* Result+Helpers.swift */; }; 57BCD3D426209D9500292CB3 /* AppTransportSecuritySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57BCD3D326209D9500292CB3 /* AppTransportSecuritySettings.swift */; }; 730E869F21E44EFD00753E1A /* WordPressComServiceRemote+SiteVerticals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 730E869E21E44EFD00753E1A /* WordPressComServiceRemote+SiteVerticals.swift */; }; 731BA83621DECD61000FDFCD /* SiteCreationRequestEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 731BA83521DECD61000FDFCD /* SiteCreationRequestEncodingTests.swift */; }; @@ -778,14 +779,15 @@ 46ABD0E9262EEE0400C7FF24 /* AppTransportSecuritySettingsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppTransportSecuritySettingsTests.swift; sourceTree = ""; }; 4A1DEF43293051BC00322608 /* LoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = ""; }; 4A1DEF45293051C600322608 /* LoggingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoggingTests.m; sourceTree = ""; }; - 4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderSite.swift; sourceTree = ""; }; - 4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderTopic.swift; sourceTree = ""; }; - 4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderSiteInfo.swift; sourceTree = ""; }; 4A68E3CC29404181004AC3DC /* RemoteBlog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteBlog.swift; sourceTree = ""; }; 4A68E3CE29404289004AC3DC /* RemoteBlogOptionsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteBlogOptionsHelper.swift; sourceTree = ""; }; 4A68E3D029406AA0004AC3DC /* RemoteMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenu.swift; sourceTree = ""; }; 4A68E3D129406AA0004AC3DC /* RemoteMenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenuItem.swift; sourceTree = ""; }; 4A68E3D229406AA0004AC3DC /* RemoteMenuLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenuLocation.swift; sourceTree = ""; }; + 4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderSite.swift; sourceTree = ""; }; + 4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderTopic.swift; sourceTree = ""; }; + 4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderSiteInfo.swift; sourceTree = ""; }; + 4A68E410294C0BDD004AC3DC /* Result+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Result+Helpers.swift"; sourceTree = ""; }; 57BCD3D326209D9500292CB3 /* AppTransportSecuritySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTransportSecuritySettings.swift; sourceTree = ""; }; 6C2A33D76FD1052D6F30466D /* Pods-WordPressKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKit/Pods-WordPressKit.debug.xcconfig"; sourceTree = ""; }; 6F2E0CC4FA01B5475A378DA2 /* Pods-WordPressKitTests.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.release-alpha.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.release-alpha.xcconfig"; sourceTree = ""; }; @@ -1606,6 +1608,7 @@ 8B2F4BEC24ABCAEF0056C08A /* Decodable+Dictionary.swift */, 8C5734F825681A6A005E61EE /* Enum+UnknownCaseRepresentable.swift */, 8B52B900257AC5A200221663 /* Date+endOfDay.swift */, + 4A68E410294C0BDD004AC3DC /* Result+Helpers.swift */, ); name = Extensions; sourceTree = ""; @@ -3181,6 +3184,7 @@ 40E7FEB4221063480032834E /* StatsTodayInsight.swift in Sources */, 436D563C2118E18D00CEAA33 /* WPState.swift in Sources */, 439A44DA2107C93000795ED7 /* RemotePlan_ApiVersion1_3.swift in Sources */, + 4A68E411294C0BDD004AC3DC /* Result+Helpers.swift in Sources */, 93BD27811EE73944002BB00B /* WordPressOrgXMLRPCApi.swift in Sources */, 439A44D62107C66A00795ED7 /* JSONDecoderExtension.swift in Sources */, B5A4822B20AC6C0B009D95F6 /* WPKitLogging.swift in Sources */, diff --git a/WordPressKit/BloggingPromptsServiceRemote.swift b/WordPressKit/BloggingPromptsServiceRemote.swift index a6cb08fe2..bf6fcb477 100644 --- a/WordPressKit/BloggingPromptsServiceRemote.swift +++ b/WordPressKit/BloggingPromptsServiceRemote.swift @@ -43,11 +43,10 @@ open class BloggingPromptsServiceRemote: ServiceRemoteWordPressComREST { return params }() - wordPressComRestApi.GET(path, parameters: requestParameter as [String: AnyObject]) { result, _ in + wordPressComRestApi.GETData(path, parameters: requestParameter as [String: AnyObject]) { result in switch result { - case .success(let responseObject): + case .success((let data, _)): do { - let data = try JSONSerialization.data(withJSONObject: responseObject, options: []) let decoder = JSONDecoder.apiDecoder // our API decoder assumes that we're converting from snake case. // revert it to default so the CodingKeys match the actual response keys. diff --git a/WordPressKit/JetpackBackupServiceRemote.swift b/WordPressKit/JetpackBackupServiceRemote.swift index 7e957e1fa..698b6c3f3 100644 --- a/WordPressKit/JetpackBackupServiceRemote.swift +++ b/WordPressKit/JetpackBackupServiceRemote.swift @@ -29,18 +29,15 @@ open class JetpackBackupServiceRemote: ServiceRemoteWordPressComREST { parameters["types"] = types.toDictionary() as AnyObject } - wordPressComRestApi.POST(path, parameters: parameters, success: { response, _ in - do { - let decoder = JSONDecoder.apiDecoder - let data = try JSONSerialization.data(withJSONObject: response, options: []) - let envelope = try decoder.decode(JetpackBackup.self, from: data) - success(envelope) - } catch { - failure(error) - } - }, failure: { error, _ in - failure(error) - }) + wordPressComRestApi.POST(path, parameters: parameters) { result in + result + .flatMap { data, _ in + Result { + try JSONDecoder.apiDecoder.decode(JetpackBackup.self, from: data) + } + } + .invoke(success, or: failure) + } } /// Get the backup download status for a site and downloadID. @@ -109,18 +106,15 @@ open class JetpackBackupServiceRemote: ServiceRemoteWordPressComREST { path = backupPath(for: siteID) } - wordPressComRestApi.GET(path, parameters: nil, success: { response, _ in - do { - let decoder = JSONDecoder.apiDecoder - let data = try JSONSerialization.data(withJSONObject: response, options: []) - let envelope = try decoder.decode(T.self, from: data) - success(envelope) - } catch { - failure(error) - } - }, failure: { error, _ in - failure(error) - }) + wordPressComRestApi.GETData(path, parameters: nil) { result in + result + .flatMap { data, _ in + Result { + try JSONDecoder.apiDecoder.decode(T.self, from: data) + } + } + .invoke(success, or: failure) + } } private func backupPath(for siteID: Int, with path: String? = nil) -> String { diff --git a/WordPressKit/JetpackScanServiceRemote.swift b/WordPressKit/JetpackScanServiceRemote.swift index 67290a5a8..8e0efc4e9 100644 --- a/WordPressKit/JetpackScanServiceRemote.swift +++ b/WordPressKit/JetpackScanServiceRemote.swift @@ -35,20 +35,15 @@ public class JetpackScanServiceRemote: ServiceRemoteWordPressComREST { public func getScanForSite(_ siteID: Int, success: @escaping(JetpackScan) -> Void, failure: @escaping(Error) -> Void) { let path = self.scanPath(for: siteID) - wordPressComRestApi.GET(path, parameters: nil, success: { (response, _) in - do { - let decoder = JSONDecoder.apiDecoder - let data = try JSONSerialization.data(withJSONObject: response, options: []) - let envelope = try decoder.decode(JetpackScan.self, from: data) - - success(envelope) - } catch { - failure(error) - } - - }, failure: { (error, _) in - failure(error) - }) + wordPressComRestApi.GETData(path, parameters: nil) { result in + result + .flatMap { data, _ in + Result { + try JSONDecoder.apiDecoder.decode(JetpackScan.self, from: data) + } + } + .invoke(success, or: failure) + } } // MARK: - Threats @@ -67,19 +62,19 @@ public class JetpackScanServiceRemote: ServiceRemoteWordPressComREST { let path = self.path(forEndpoint: "sites/\(siteID)/alerts/fix", withVersion: ._2_0) let parameters = ["threat_ids": threats.map { $0.id as AnyObject }] as [String: AnyObject] - wordPressComRestApi.POST(path, parameters: parameters, success: { (response, _) in - do { - let decoder = JSONDecoder.apiDecoder - let data = try JSONSerialization.data(withJSONObject: response, options: []) - let envelope = try decoder.decode(JetpackThreatFixResponse.self, from: data) - - success(envelope) - } catch { + wordPressComRestApi.POST(path, parameters: parameters) { result in + let transformed = result.flatMap { data, _ in + Result { + try JSONDecoder.apiDecoder.decode(JetpackThreatFixResponse.self, from: data) + } + } + switch transformed { + case let .success(response): + success(response) + case let .failure(error): failure(error) } - }, failure: { (error, _) in - failure(error) - }) + } } /// Begins the fix process for a single threat @@ -113,38 +108,30 @@ public class JetpackScanServiceRemote: ServiceRemoteWordPressComREST { let path = self.path(forEndpoint: "sites/\(siteID)/alerts/fix", withVersion: ._2_0) let parameters = ["threat_ids": threats.map { $0.id as AnyObject }] as [String: AnyObject] - wordPressComRestApi.GET(path, parameters: parameters, success: { (response, _) in - do { - let decoder = JSONDecoder.apiDecoder - let data = try JSONSerialization.data(withJSONObject: response, options: []) - let envelope = try decoder.decode(JetpackThreatFixResponse.self, from: data) - - success(envelope) - } catch { - failure(error) - } - }, failure: { (error, _) in - failure(error) - }) + wordPressComRestApi.GETData(path, parameters: parameters) { result in + result + .flatMap { data, _ in + Result { + try JSONDecoder.apiDecoder.decode(JetpackThreatFixResponse.self, from: data) + } + } + .invoke(success, or: failure) + } } // MARK: - History public func getHistoryForSite(_ siteID: Int, success: @escaping(JetpackScanHistory) -> Void, failure: @escaping(Error) -> Void) { let path = scanPath(for: siteID, with: "history") - wordPressComRestApi.GET(path, parameters: nil, success: { (response, _) in - do { - let decoder = JSONDecoder.apiDecoder - let data = try JSONSerialization.data(withJSONObject: response, options: []) - let envelope = try decoder.decode(JetpackScanHistory.self, from: data) - - success(envelope) - } catch { - failure(error) - } - }, failure: { (error, _) in - failure(error) - }) + wordPressComRestApi.GETData(path, parameters: nil) { result in + result + .flatMap { data, _ in + Result { + try JSONDecoder.apiDecoder.decode(JetpackScanHistory.self, from: data) + } + } + .invoke(success, or: failure) + } } // MARK: - Private diff --git a/WordPressKit/Result+Helpers.swift b/WordPressKit/Result+Helpers.swift new file mode 100644 index 000000000..8d6790e75 --- /dev/null +++ b/WordPressKit/Result+Helpers.swift @@ -0,0 +1,12 @@ +extension Result { + + func invoke(_ success: ((Success) -> Void)?, or failure: ((Failure) -> Void)?) { + switch self { + case let.success(result): + success?(result) + case let .failure(error): + failure?(error) + } + } + +} diff --git a/WordPressKit/ShareAppContentServiceRemote.swift b/WordPressKit/ShareAppContentServiceRemote.swift index ad1670290..14ec64a6d 100644 --- a/WordPressKit/ShareAppContentServiceRemote.swift +++ b/WordPressKit/ShareAppContentServiceRemote.swift @@ -11,20 +11,14 @@ open class ShareAppContentServiceRemote: ServiceRemoteWordPressComREST { let requestURLString = path(forEndpoint: endpoint, withVersion: ._2_0) let params: [String: AnyObject] = [Constants.appNameParameterKey: appName.rawValue as AnyObject] - wordPressComRestApi.GET(requestURLString, parameters: params) { result, _ in - switch result { - case .success(let responseObject): - do { - let data = try JSONSerialization.data(withJSONObject: responseObject, options: []) - let content = try JSONDecoder.apiDecoder.decode(RemoteShareAppContent.self, from: data) - completion(.success(content)) - } catch { - completion(.failure(error)) + wordPressComRestApi.GETData(requestURLString, parameters: params) { result in + completion( + result.flatMap { data, _ in + Result { + try JSONDecoder.apiDecoder.decode(RemoteShareAppContent.self, from: data) + } } - - case .failure(let error): - completion(.failure(error)) - } + ) } } } diff --git a/WordPressKit/TransactionsServiceRemote.swift b/WordPressKit/TransactionsServiceRemote.swift index 956ffac2d..195e8195c 100644 --- a/WordPressKit/TransactionsServiceRemote.swift +++ b/WordPressKit/TransactionsServiceRemote.swift @@ -16,24 +16,15 @@ import WordPressShared let endPoint = "me/transactions/supported-countries/" let servicePath = path(forEndpoint: endPoint, withVersion: ._1_1) - wordPressComRestApi.GET(servicePath, - parameters: nil, - success: { - response, _ in - do { - guard let json = response as? [AnyObject] else { - throw ResponseError.decodingFailure - } - let data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) - let decodedResult = try JSONDecoder.apiDecoder.decode([WPCountry].self, from: data) - success(decodedResult) - } catch { - WPKitLogError("Error parsing Supported Countries (\(error)): \(response)") - failure(error) - } - }, failure: { error, _ in - failure(error) - }) + wordPressComRestApi.GETData(servicePath, parameters: nil) { result in + result + .flatMap { data, _ in + Result { + try JSONDecoder.apiDecoder.decode([WPCountry].self, from: data) + } + } + .invoke(success, or: failure) + } } /// Creates a shopping cart for a domain purchase diff --git a/WordPressKit/WordPressComRestApi.swift b/WordPressKit/WordPressComRestApi.swift index 1b4fe0d63..b0de32e29 100644 --- a/WordPressKit/WordPressComRestApi.swift +++ b/WordPressKit/WordPressComRestApi.swift @@ -271,6 +271,22 @@ open class WordPressComRestApi: NSObject { completion: completion) } + + /** + Executes a POST request to the specified endpoint defined on URLString + + - parameter URLString: the url string to be added to the baseURL + - parameter parameters: the parameters to be encoded on the request + - returns completion: callback to receive the response + */ + open func POST( + _ URLString: String, + parameters: [String: AnyObject]?, + completion: @escaping (Swift.Result<(Data, HTTPURLResponse?), Error>) -> Void + ) { + dataRequest(method: .post, urlString: URLString, parameters: parameters, encoding: JSONEncoding.default, completion: completion) + } + /** Executes a POST request to the specified endpoint defined on URLString diff --git a/WordPressKitTests/MockWordPressComRestApi.swift b/WordPressKitTests/MockWordPressComRestApi.swift index 24efa46b3..57fd263e0 100644 --- a/WordPressKitTests/MockWordPressComRestApi.swift +++ b/WordPressKitTests/MockWordPressComRestApi.swift @@ -19,6 +19,18 @@ class MockWordPressComRestApi: WordPressComRestApi { return Progress() } + override func GETData(_ URLString: String, parameters: [String: AnyObject]?, completion: @escaping (Result<(Data, HTTPURLResponse?), Error>) -> Void) { + getMethodCalled = true + URLStringPassedIn = URLString + parametersPassedIn = parameters as AnyObject? + } + + override func POST(_ URLString: String, parameters: [String: AnyObject]?, completion: @escaping (Result<(Data, HTTPURLResponse?), Error>) -> Void) { + postMethodCalled = true + URLStringPassedIn = URLString + parametersPassedIn = parameters as AnyObject? + } + override func POST(_ URLString: String?, parameters: [String: AnyObject]?, success: @escaping ((AnyObject, HTTPURLResponse?) -> Void), failure: @escaping ((NSError, HTTPURLResponse?) -> Void)) -> Progress? { postMethodCalled = true URLStringPassedIn = URLString