From 43a486f2a3e0e2783b1645a3e762ee57794acdaf Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Mon, 5 Sep 2022 22:46:23 +0900 Subject: [PATCH 1/4] group concurrency functions --- Sources/RequestKit/Router.swift | 57 +++++++++++++++++---------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/Sources/RequestKit/Router.swift b/Sources/RequestKit/Router.swift index d4e1071..32fd89a 100644 --- a/Sources/RequestKit/Router.swift +++ b/Sources/RequestKit/Router.swift @@ -194,8 +194,34 @@ public extension Router { return task } - #if compiler(>=5.5.2) && canImport(_Concurrency) - @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func load(_ session: RequestKitURLSession = URLSession.shared, completion: @escaping (_ error: Error?) -> Void) -> URLSessionDataTaskProtocol? { + guard let request = request() else { + return nil + } + + let task = session.dataTask(with: request) { data, response, err in + if let response = response as? HTTPURLResponse { + if response.wasSuccessful == false { + var userInfo = [String: Any]() + if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] { + userInfo[RequestKitErrorKey] = json as Any? + } + let error = NSError(domain: self.configuration.errorDomain, code: response.statusCode, userInfo: userInfo) + completion(error) + return + } + } + + completion(err) + } + task.resume() + return task + } +} + +#if compiler(>=5.5.2) && canImport(_Concurrency) +@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +public extension Router { func load(_ session: RequestKitURLSession = URLSession.shared, decoder: JSONDecoder = JSONDecoder(), expectedResultType _: T.Type) async throws -> T { guard let request = request() else { throw NSError(domain: configuration.errorDomain, code: -876, userInfo: nil) @@ -216,7 +242,6 @@ public extension Router { return try decoder.decode(T.self, from: responseTuple.0) } - @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) func load(_ session: RequestKitURLSession = URLSession.shared, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy?, expectedResultType: T.Type) async throws -> T { let decoder = JSONDecoder() if let dateDecodingStrategy = dateDecodingStrategy { @@ -224,32 +249,8 @@ public extension Router { } return try await load(session, decoder: decoder, expectedResultType: expectedResultType) } - #endif - - func load(_ session: RequestKitURLSession = URLSession.shared, completion: @escaping (_ error: Error?) -> Void) -> URLSessionDataTaskProtocol? { - guard let request = request() else { - return nil - } - - let task = session.dataTask(with: request) { data, response, err in - if let response = response as? HTTPURLResponse { - if response.wasSuccessful == false { - var userInfo = [String: Any]() - if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] { - userInfo[RequestKitErrorKey] = json as Any? - } - let error = NSError(domain: self.configuration.errorDomain, code: response.statusCode, userInfo: userInfo) - completion(error) - return - } - } - - completion(err) - } - task.resume() - return task - } } +#endif private extension CharacterSet { // https://github.com/Alamofire/Alamofire/blob/3.5rameterEncoding.swift#L220-L225 From 02b2382e5b0589a78932694c0dfda9e83b09c489 Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Mon, 5 Sep 2022 23:14:14 +0900 Subject: [PATCH 2/4] add `load` function for the requests whose response body will be empty or can be ignored --- Sources/RequestKit/Router.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Sources/RequestKit/Router.swift b/Sources/RequestKit/Router.swift index 32fd89a..07fa1bd 100644 --- a/Sources/RequestKit/Router.swift +++ b/Sources/RequestKit/Router.swift @@ -249,6 +249,23 @@ public extension Router { } return try await load(session, decoder: decoder, expectedResultType: expectedResultType) } + + func load(_ session: RequestKitURLSession = URLSession.shared) async throws { + guard let request = request() else { + throw NSError(domain: configuration.errorDomain, code: -876, userInfo: nil) + } + + let responseTuple = try await session.data(for: request, delegate: nil) + if let response = responseTuple.1 as? HTTPURLResponse { + if response.wasSuccessful == false { + var userInfo = [String: Any]() + if let json = try? JSONSerialization.jsonObject(with: responseTuple.0, options: .mutableContainers) as? [String: Any] { + userInfo[RequestKitErrorKey] = json as Any? + } + throw NSError(domain: configuration.errorDomain, code: response.statusCode, userInfo: userInfo) + } + } + } } #endif From 4e454b4c474397691f7ccecfc7f809637eca98a6 Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Mon, 5 Sep 2022 23:14:51 +0900 Subject: [PATCH 3/4] add test for new `load` function --- Tests/RequestKitTests/RouterTests.swift | 17 +++++++++++++++++ Tests/RequestKitTests/TestInterface.swift | 8 ++++++++ 2 files changed, 25 insertions(+) diff --git a/Tests/RequestKitTests/RouterTests.swift b/Tests/RequestKitTests/RouterTests.swift index 9d672ef..f2630f1 100644 --- a/Tests/RequestKitTests/RouterTests.swift +++ b/Tests/RequestKitTests/RouterTests.swift @@ -143,6 +143,23 @@ class RouterTests: XCTestCase { XCTAssertTrue(session.wasCalled) XCTAssertTrue(receivedFailureResponse) } + + #if compiler(>=5.5.2) && canImport(_Concurrency) + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func testEmptyResponseWithLoadAndIgnoreResponseBodyAsync() async throws { + let session = RequestKitURLTestSession(expectedURL: "https://example.com/some_route", expectedHTTPMethod: "POST", response: "", statusCode: 204) + + var receivedSuccessResponse = false + do { + _ = try await TestInterface().loadAndIgnoreResponseBody(session) + receivedSuccessResponse = true + } catch { + XCTFail("should not catch any error") + } + XCTAssertTrue(session.wasCalled) + XCTAssertTrue(receivedSuccessResponse) + } + #endif } enum TestRouter: Router { diff --git a/Tests/RequestKitTests/TestInterface.swift b/Tests/RequestKitTests/TestInterface.swift index 7c4c8bb..543e816 100644 --- a/Tests/RequestKitTests/TestInterface.swift +++ b/Tests/RequestKitTests/TestInterface.swift @@ -67,6 +67,14 @@ class TestInterface { } } } + + #if compiler(>=5.5.2) && canImport(_Concurrency) + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func loadAndIgnoreResponseBody(_ session: RequestKitURLSession) async throws { + let router = JSONTestRouter.testPOST(configuration) + return try await router.load(session) + } + #endif } enum JSONTestRouter: JSONPostRouter { From 7d0f035e322ee991edc462b80c3c0a48f0682d2c Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Mon, 5 Sep 2022 23:16:58 +0900 Subject: [PATCH 4/4] add async/await functions to protocol --- Sources/RequestKit/Router.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sources/RequestKit/Router.swift b/Sources/RequestKit/Router.swift index 07fa1bd..f09a1f4 100644 --- a/Sources/RequestKit/Router.swift +++ b/Sources/RequestKit/Router.swift @@ -63,6 +63,15 @@ public protocol Router { completion: @escaping (_ json: T?, _ error: Error?) -> Void) -> URLSessionDataTaskProtocol? func load(_ session: RequestKitURLSession, decoder: JSONDecoder, expectedResultType: T.Type, completion: @escaping (_ json: T?, _ error: Error?) -> Void) -> URLSessionDataTaskProtocol? func request() -> URLRequest? + + #if compiler(>=5.5.2) && canImport(_Concurrency) + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func load(_ session: RequestKitURLSession, decoder: JSONDecoder, expectedResultType _: T.Type) async throws -> T + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func load(_ session: RequestKitURLSession, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy?, expectedResultType: T.Type) async throws -> T + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func load(_ session: RequestKitURLSession) async throws + #endif } public extension Router {