Skip to content

Instantly share code, notes, and snippets.

@daniyalyousuf07
Created February 24, 2023 11:34
Show Gist options
  • Save daniyalyousuf07/b6d943fe43356f9aac3ad99849fca867 to your computer and use it in GitHub Desktop.
Save daniyalyousuf07/b6d943fe43356f9aac3ad99849fca867 to your computer and use it in GitHub Desktop.
A demo of Dependency Inversion Principle (DIP) & Example of network mocking
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#>)
@daniyalyousuf07
Copy link
Author

A demo of Dependency Inversion Principle (DIP) & Example of network mocking

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment