Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor data provider service to use new request coordinator protocol
- Loading branch information
Showing
8 changed files
with
150 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// | ||
// RequestCoordinator.swift | ||
// AmuseKit | ||
// | ||
// Created by Jota Uribe on 30/09/22. | ||
// | ||
|
||
import Combine | ||
import Foundation | ||
|
||
public typealias RequestResult<T> = Result<T, Error> | ||
|
||
public protocol RequestDecoder { | ||
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T: Decodable | ||
} | ||
|
||
extension JSONDecoder: RequestDecoder { } | ||
|
||
public protocol RequestCoordinator { | ||
func dataTask<T: Codable>(request: URLRequest, decoder: RequestDecoder, completion: @escaping (RequestResult<T>) -> Void) | ||
@available(iOS 15.0, *) | ||
@available(macOS 12.0, *) | ||
func data<T: Codable>(request: URLRequest, decoder: RequestDecoder) async throws -> RequestResult<T> | ||
func dataTaskPublisher<T: Codable>(for request: URLRequest, decoder: RequestDecoder) throws -> AnyPublisher<T, Error> | ||
} | ||
|
||
extension URLSession: RequestCoordinator { | ||
public func dataTask<T>(request: URLRequest, decoder: RequestDecoder, completion: @escaping (RequestResult<T>) -> Void) where T : Decodable, T : Encodable { | ||
dataTask(with: request) { data, response, error in | ||
if let error = error { | ||
completion(.failure(error)) | ||
} | ||
|
||
guard let data = data else { | ||
completion(.failure(URLError(.badServerResponse))) | ||
return | ||
} | ||
|
||
do { | ||
let decodedData = try decoder.decode(T.self, from: data) | ||
completion(.success(decodedData)) | ||
} catch { | ||
completion(.failure(error)) | ||
} | ||
}.resume() | ||
} | ||
|
||
@available(iOS 15.0, *) | ||
@available(macOS 12.0, *) | ||
public func data<T>(request: URLRequest, decoder: RequestDecoder) async throws -> RequestResult<T> where T : Decodable, T : Encodable { | ||
let data: (Data, URLResponse) = try await data(for: request) | ||
return Result { | ||
try decoder.decode(T.self, from: data.0) | ||
} | ||
} | ||
|
||
public func dataTaskPublisher<T>(for request: URLRequest, decoder: RequestDecoder) throws -> AnyPublisher<T, Error> where T : Decodable, T : Encodable { | ||
return dataTaskPublisher(for: request) | ||
.tryMap { try decoder.decode(T.self, from: $0.data) } | ||
.eraseToAnyPublisher() | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// | ||
// MockAPIService.swift | ||
// AmuseKit | ||
// | ||
// Created by Jota Uribe on 22/03/21. | ||
// | ||
|
||
import Combine | ||
import Foundation | ||
@testable import AmuseKit | ||
|
||
enum MockAPIServiceError: Error { | ||
case invalidFilePath(endpoint: String) | ||
case invalidFileFormat | ||
} | ||
|
||
struct MockRequestCoordinator: RequestCoordinator { | ||
var resourceName: String = "" | ||
|
||
func dataTask<T>(request: URLRequest, decoder: RequestDecoder, completion: @escaping (RequestResult<T>) -> Void) where T : Decodable, T : Encodable { | ||
guard let filePath = Bundle.module.path(forResource: resourceName, ofType: "json") else { | ||
completion(.failure(MockAPIServiceError.invalidFilePath(endpoint: resourceName))) | ||
return | ||
} | ||
|
||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: filePath), options: .mappedIfSafe) else { | ||
completion(.failure(MockAPIServiceError.invalidFileFormat)) | ||
return | ||
} | ||
|
||
do { | ||
let response = try decoder.decode(T.self, from: data) | ||
completion(.success(response)) | ||
} catch { | ||
completion(.failure(error)) | ||
} | ||
} | ||
|
||
func data<T>(request: URLRequest, decoder: RequestDecoder) async throws -> RequestResult<T> where T : Decodable, T : Encodable { | ||
guard let filePath = Bundle.module.path(forResource: resourceName, ofType: "json") else { | ||
throw MockAPIServiceError.invalidFilePath(endpoint: resourceName) | ||
} | ||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: filePath), options: .mappedIfSafe) else { | ||
throw MockAPIServiceError.invalidFileFormat | ||
} | ||
|
||
do { | ||
let response = try decoder.decode(T.self, from: data) | ||
return .success(response) | ||
} catch { | ||
return .failure(error) | ||
} | ||
} | ||
|
||
func dataTaskPublisher<T>(for request: URLRequest, decoder: RequestDecoder) throws -> AnyPublisher<T, Error> where T : Decodable, T : Encodable { | ||
guard let filePath = Bundle.module.path(forResource: resourceName, ofType: "json") else { | ||
throw MockAPIServiceError.invalidFilePath(endpoint: resourceName) | ||
} | ||
|
||
let publisher = filePath.publisher.collect().map { String($0) } | ||
.setFailureType(to: MockAPIServiceError.self) | ||
.tryMap({ path -> T in | ||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) else { | ||
throw MockAPIServiceError.invalidFileFormat | ||
} | ||
return try decoder.decode(T.self, from: data) | ||
}) | ||
.eraseToAnyPublisher() | ||
return publisher | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters