Last active
December 13, 2022 07:22
-
-
Save mrugeshtank/4ba6a3fca46e88bb229c4ca48daafd35 to your computer and use it in GitHub Desktop.
This file is a walkthrough of an article by Donny Wals at https://www.donnywals.com/architecting-a-robust-networking-layer-with-protocols/
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 | |
struct Feed: Decodable { | |
} | |
class FeedViewModel { | |
let service: FeedProviding | |
var feed: Feed? | |
var onFeedUpdate: () -> Void = {} | |
init(service: FeedProviding) { | |
self.service = service | |
} | |
func fetch() { | |
service.getFeed { result in | |
do { | |
self.feed = try result.get() | |
self.onFeedUpdate() | |
} catch { | |
// handle error | |
} | |
} | |
} | |
} | |
protocol FeedProviding { | |
var network: Networking { get } | |
func getFeed(_ completion: @escaping (Result<Feed, Error>) -> Void) | |
} | |
extension FeedProviding { | |
func getFeed(_ completion: @escaping (Result<Feed, Error>) -> Void) { | |
network.execute(Endpoint.feed, completion: completion) | |
} | |
} | |
protocol Networking { | |
func execute<T: Decodable>(_ requestProvider: Endpoint, completion: @escaping (Result<T, Error>) -> Void) | |
} | |
enum Endpoint { | |
case feed | |
} | |
extension Networking { | |
func execute<T: Decodable>(_ requestProvider: Endpoint, completion: @escaping (Result<T, Error>) -> Void) { | |
let urlRequest = requestProvider.urlRequest | |
URLSession.shared.dataTask(with: urlRequest) { data, response, error in | |
do { | |
if let error = error { | |
completion(.failure(error)) | |
return | |
} | |
guard let data = data else { | |
preconditionFailure("No error was received but we also don't have data...") | |
} | |
let decodedObject = try JSONDecoder().decode(T.self, from: data) | |
completion(.success(decodedObject)) | |
} catch { | |
completion(.failure(error)) | |
} | |
}.resume() | |
} | |
} | |
protocol RequestProviding { | |
var urlRequest: URLRequest { get } | |
} | |
extension Endpoint: RequestProviding { | |
var urlRequest: URLRequest { | |
switch self { | |
case .feed: | |
guard let url = URL(string: "https://mydomain.com/feed") else { | |
preconditionFailure("Invalid URL used to create URL instance") | |
} | |
return URLRequest(url: url) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment