Created
February 24, 2023 11:34
-
-
Save daniyalyousuf07/b6d943fe43356f9aac3ad99849fca867 to your computer and use it in GitHub Desktop.
A demo of Dependency Inversion Principle (DIP) & Example of network mocking
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
import Foundation | |
protocol APIHandlerProtocol { | |
func fetchData(url: URL, | |
completion: @escaping(Result<Data, | |
DemoError>) -> Void) | |
} | |
protocol ResponseHandlerProtocol { | |
func parseData<T:Codable>(type: T.Type, | |
data: Data, | |
completion: @escaping(Result<T, DemoError>) -> Void) | |
} | |
class AppNetworkManageR { | |
let apiHandler: APIHandlerProtocol | |
let responseHandler: ResponseHandlerProtocol | |
init(apiHandler: APIHandlerProtocol = APIHandleR(), | |
responseHandler: ResponseHandlerProtocol = ResponseHandleR()) { | |
self.apiHandler = apiHandler | |
self.responseHandler = responseHandler | |
} | |
func fetchRequest<T: Codable>(type: T.Type, | |
url: URL, | |
completion: @escaping (Result<T, DemoError>) -> Void) { | |
apiHandler.fetchData(url: url) {[weak self] result in | |
switch result { | |
case .failure(let error): | |
completion(.failure(error)) | |
case .success(let data): | |
self?.responseHandler.parseData(type: type, | |
data: data) { result in | |
switch result { | |
case .failure(let error): | |
completion(.failure(error)) | |
case .success(let model): | |
completion(.success(model)) | |
} | |
} | |
} | |
} | |
} | |
} | |
class APIHandleR: APIHandlerProtocol { | |
func fetchData(url: URL, | |
completion: @escaping(Result<Data, | |
DemoError>) -> Void) { | |
URLSession.shared.dataTask(with: url) { data, response, error in | |
guard let data = data, error == nil else { | |
return completion(.failure(.noData)) | |
} | |
completion(.success(data)) | |
}.resume() | |
} | |
} | |
class ResponseHandleR: ResponseHandlerProtocol { | |
func parseData<T:Codable>(type: T.Type, | |
data: Data, | |
completion: @escaping(Result<T, DemoError>) -> Void) { | |
let parseModel = try? JSONDecoder().decode(type.self, | |
from: data) | |
if let parseModel = parseModel { | |
return completion(.success(parseModel)) | |
} else { | |
return completion(.failure(.decodingError)) | |
} | |
} | |
} | |
/** | |
In this example, we have defined protocols APIHandlerProtocol and ResponseHandlerProtocol that define the methods required for network requests. We then extend the APIHandleR & ResponseHandleR classes to conform to these protocol. | |
The AppNetworkManageR class now depends on the ResponseHandlerProtocol & APIHandlerProtocol abstraction, rather than the URLSession & JSONDecorder() classes directly. This allows us to provide a different implementation of the APIHandlerProtocol & ResponseHandlerProtocol in the future, without having to modify the AppNetworkManageR class. | |
For example, we can create a mock implementation of the APIHandlerProtocol & ResponseHandlerProtocol for testing purposes: | |
*/ | |
class APIHandlerMock: APIHandlerProtocol { | |
func fetchData(url: URL, completion: @escaping (Result<Data, DemoError>) -> Void) { | |
// fetching data from another URL for testing purpose | |
} | |
} | |
class ResponseHandlerMock: ResponseHandlerProtocol { | |
func parseData<T>(type: T.Type, data: Data, completion: @escaping (Result<T, DemoError>) -> Void) where T : Decodable, T : Encodable { | |
} | |
} | |
let mockNetworkLayer = AppNetworkManageR(apiHandler: APIHandlerMock(), responseHandler: ResponseHandlerMock()) | |
//mockNetworkLayer.fetchRequest(type: <#T##(Decodable & Encodable).Protocol#>, | |
// url: <#T##URL#>, | |
// completion: <#T##(Result<Decodable & Encodable, DemoError>) -> Void#>) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A demo of Dependency Inversion Principle (DIP) & Example of network mocking