Made the AmiiboClient client and the AmiiboService service available for non-Apple platforms by importing the FoundationNetworking framework.

This commit is contained in:
Javier Cicchelli 2023-04-30 15:48:05 +02:00
parent 9812366575
commit f2821e458b
6 changed files with 45 additions and 13 deletions

View File

@ -10,16 +10,18 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Communications import Communications
import Foundation import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
struct AmiiboClient { struct AmiiboClient {
// MARK: Properties // MARK: Properties
private let session: URLSession private let session: URLSession
private let decoder = JSONDecoder() private let decoder = JSONDecoder()
private let makeURLRequest = MakeURLRequestUseCase() private let makeURLRequest = MakeURLRequestUseCase()
@ -48,7 +50,7 @@ extension AmiiboClient: Client {
as model: Model.Type as model: Model.Type
) async throws -> Model where Model : Decodable { ) async throws -> Model where Model : Decodable {
let urlRequest = try makeURLRequest(endpoint: endpoint) let urlRequest = try makeURLRequest(endpoint: endpoint)
let (data, response) = try await session.data(for: urlRequest) let (data, response) = try await data(from: session, for: urlRequest)
try check(response) try check(response)
@ -62,6 +64,27 @@ extension AmiiboClient: Client {
private extension AmiiboClient { private extension AmiiboClient {
// MARK: Functions // MARK: Functions
func data(
from session: URLSession,
for urlRequest: URLRequest
) async throws -> (Data, URLResponse) {
#if canImport(FoundationNetworking)
try await withCheckedThrowingContinuation { continuation in
session.dataTask(with: urlRequest) { data, response, error in
if let error {
continuation.resume(with: .failure(error))
} else if let data, let response {
continuation.resume(with: .success((data, response)))
} else {
continuation.resume(with: .failure(AmiiboClientError.dataOrResponseNotFound))
}
}
}
#else
try await session.data(for: urlRequest)
#endif
}
func check(_ response: URLResponse) throws { func check(_ response: URLResponse) throws {
guard guard
@ -77,4 +100,3 @@ private extension AmiiboClient {
} }
} }
#endif

View File

@ -12,6 +12,8 @@
/// This error definitions represents any error happening while the client makes a request to the remote API and handles the respective response, excluding the decoding of the retrieved data into a particular model. /// This error definitions represents any error happening while the client makes a request to the remote API and handles the respective response, excluding the decoding of the retrieved data into a particular model.
public enum AmiiboClientError: Error { public enum AmiiboClientError: Error {
/// The data and/or response expected from an API call are not found.
case dataOrResponseNotFound
/// The status code of the response is not the expected one, which is `.ok` (`200`). /// The status code of the response is not the expected one, which is `.ok` (`200`).
case responseCode(Int) case responseCode(Int)
/// The status code of the response was not received at all. /// The status code of the response was not received at all.

View File

@ -10,9 +10,12 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Foundation import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
/// This service provides the interface to make remote API calls to the [Amiibo API](https://www.amiiboapi.com) and, subsequently, handle its responses. /// This service provides the interface to make remote API calls to the [Amiibo API](https://www.amiiboapi.com) and, subsequently, handle its responses.
/// ///
/// Given that this remote service is a read-only API, this service will exclusively return decoded models or entities in cases the requests are successful, or it will throw errors otherwise. /// Given that this remote service is a read-only API, this service will exclusively return decoded models or entities in cases the requests are successful, or it will throw errors otherwise.
@ -125,5 +128,4 @@ extension AmiiboService: Service {
).timestamp ).timestamp
} }
} }
#endif

View File

@ -10,11 +10,14 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Communications import Communications
import Foundation import Foundation
import XCTest import XCTest
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
@testable import AmiiboService @testable import AmiiboService
final class AmiiboClientTests: XCTestCase { final class AmiiboClientTests: XCTestCase {
@ -156,4 +159,3 @@ final class AmiiboClientTests: XCTestCase {
} }
} }
#endif

View File

@ -10,10 +10,13 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Communications import Communications
import Foundation import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
extension MockURLRequest { extension MockURLRequest {
// MARK: Initialisers // MARK: Initialisers
@ -23,4 +26,3 @@ extension MockURLRequest {
} }
} }
#endif

View File

@ -10,11 +10,14 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Communications import Communications
import Foundation import Foundation
import XCTest import XCTest
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
@testable import AmiiboService @testable import AmiiboService
final class AmiiboServiceTests: XCTestCase { final class AmiiboServiceTests: XCTestCase {
@ -522,4 +525,3 @@ final class AmiiboServiceTests: XCTestCase {
} }
} }
#endif