From e6e5f77d6cca841076f1663bd2fbff17a11d1a07 Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 29 Dec 2021 18:21:53 -0500 Subject: [PATCH] Add send optional variant --- CHANGELOG.md | 6 ++++++ README.md | 2 +- Sources/Get/APIClient.swift | 11 +++++++++++ Sources/Get/Helpers.swift | 4 ++-- Tests/GetTests/ClientTests.swift | 27 +++++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 507cec2..c4353b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Get 0.x +## Get 0.3.0 + +*Dec 29, 2021* + +- Add `send` variant that works with optional types. If the response is empty – return `nil`. + ## Get 0.2.1 *Dec 24, 2021* diff --git a/README.md b/README.md index 3277d58..c42359a 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ public struct Response { } ``` -The response can be any `Decodable` type. And if the response type is `Data`, the client simply returns raw response data. If it's a `String`, it returns the response as plain text. +The response can be any `Decodable` type. The response can also be optional. And if the response type is `Data`, the client simply returns raw response data. If it's a `String`, it returns the response as plain text. > If you just want to retrieve the response data, you can also call `data(for:)`. diff --git a/Sources/Get/APIClient.swift b/Sources/Get/APIClient.swift index 1bd56e0..1f7c751 100644 --- a/Sources/Get/APIClient.swift +++ b/Sources/Get/APIClient.swift @@ -59,6 +59,17 @@ public actor APIClient { self.serializer = Serializer(decoder: configuration.decoder, encoder: configuration.encoder) } + /// Sends the given request and returns a response with a decoded response value. + public func send(_ request: Request) async throws -> Response { + try await send(request) { data in + if data.isEmpty { + return nil + } else { + return try await self.serializer.decode(data) + } + } + } + /// Sends the given request and returns a response with a decoded response value. public func send(_ request: Request) async throws -> Response { try await send(request) { data in diff --git a/Sources/Get/Helpers.swift b/Sources/Get/Helpers.swift index ac4d234..595371d 100644 --- a/Sources/Get/Helpers.swift +++ b/Sources/Get/Helpers.swift @@ -98,8 +98,8 @@ final class DataLoader: NSObject, URLSessionDataDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { guard let handler = handlers[task] else { return } handlers[task] = nil - if let data = handler.data, let response = task.response, error == nil { - handler.completion(.success((data, response, handler.metrics))) + if let response = task.response, error == nil { + handler.completion(.success((handler.data ?? Data(), response, handler.metrics))) } else { handler.completion(.failure(error ?? URLError(.unknown))) } diff --git a/Tests/GetTests/ClientTests.swift b/Tests/GetTests/ClientTests.swift index 9b62bc5..46da8a5 100644 --- a/Tests/GetTests/ClientTests.swift +++ b/Tests/GetTests/ClientTests.swift @@ -91,6 +91,33 @@ final class APIClientTests: XCTestCase { // THEN returns decoded JSON XCTAssertEqual(user.login, "kean") } + + // func value(for:) -> Decodable + func testResponseDecodableOptional() async throws { + // GIVEN + let url = URL(string: "https://api.github.com/user")! + Mock(url: url, dataType: .html, statusCode: 200, data: [ + .get: Data() + ]).register() + + // WHEN + let user: User? = try await client.send(.get("/user")).value + + // THEN returns decoded JSON + XCTAssertNil(user) + } + + // func value(for:) -> Decodable + func testResponseEmpty() async throws { + // GIVEN + let url = URL(string: "https://api.github.com/user")! + Mock(url: url, dataType: .html, statusCode: 200, data: [ + .get: Data() + ]).register() + + // WHEN + try await client.send(.get("/user")).value + } // func value(for:) -> Data func testResponseData() async throws {