diff --git a/Sources/Clients/AmiiboClient.swift b/Sources/Clients/AmiiboClient.swift new file mode 100644 index 0000000..170b829 --- /dev/null +++ b/Sources/Clients/AmiiboClient.swift @@ -0,0 +1,66 @@ +import Communications +import Foundation + +struct AmiiboClient { + + // MARK: Properties + + private let session: URLSession + + private let decoder = JSONDecoder() + private let makeURLRequest = MakeURLRequestUseCase() + + // MARK: Initialisers + + init(configuration: URLSessionConfiguration) { + session = .init(configuration: configuration) + } + + // MARK: Functions + + func setDateDecodingStrategy(_ dateDecodingStrategy: JSONDecoder.DateDecodingStrategy) { + decoder.dateDecodingStrategy = dateDecodingStrategy + } + +} + +// MARK: - Client + +extension AmiiboClient: Client { + + // MARK: Functions + + func request( + endpoint: some Endpoint, + as model: Model.Type + ) async throws -> Model where Model : Decodable { + let urlRequest = try makeURLRequest(endpoint: endpoint) + let (data, response) = try await session.data(for: urlRequest) + + try check(response) + + return try decoder.decode(model, from: data) + } + +} + +// MARK: - Helpers + +private extension AmiiboClient { + + // MARK: Functions + + func check(_ response: URLResponse) throws { + guard + let urlResponse = response as? HTTPURLResponse, + let responseCode = HTTPResponseCode(rawValue: urlResponse.statusCode) + else { + throw AmiiboClientError.responseCodeNotFound + } + + guard responseCode == .ok else { + throw AmiiboClientError.responseCode(responseCode.rawValue) + } + } + +} diff --git a/Sources/Errors/AmiiboClientError.swift b/Sources/Errors/AmiiboClientError.swift new file mode 100644 index 0000000..6e49f0c --- /dev/null +++ b/Sources/Errors/AmiiboClientError.swift @@ -0,0 +1,4 @@ +public enum AmiiboClientError: Error { + case responseCode(Int) + case responseCodeNotFound +} diff --git a/Tests/Clients/AmiiboClientTests.swift b/Tests/Clients/AmiiboClientTests.swift new file mode 100644 index 0000000..b143b72 --- /dev/null +++ b/Tests/Clients/AmiiboClientTests.swift @@ -0,0 +1,42 @@ +import Communications +import Foundation +import XCTest + +@testable import AmiiboService + +final class AmiiboClientTests: XCTestCase { + + // MARK: Properties + + private let configuration: URLSessionConfiguration = { + let configuration = URLSessionConfiguration.ephemeral + + configuration.protocolClasses = [MockURLProtocol.self] + + return configuration + }() + + private var client: AmiiboClient! + private var request: MockURLRequest! + private var response: MockURLResponse! + + // MARK: Setup + + override func setUp() async throws { + client = .init(configuration: configuration) + } + + override func tearDown() async throws { + client = nil + } + + // MARK: Tests + + func test_withSomething() async throws { + // GIVEN + // WHEN + // THEN + XCTFail("Not implemented yet") + } + +}